diff options
author | Mark Brown <broonie@kernel.org> | 2018-01-25 21:16:26 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-01-25 21:16:26 +0300 |
commit | 0b5eca67bd2d0e6f6d0ccdc316aced0cc4bf2e9f (patch) | |
tree | b6597ffe774a67ab5b8eebd57c9a723732d3a39c /sound | |
parent | 3bb0f7c31b1aedd0f85c675297031281799145d7 (diff) | |
parent | 93a00c467fe998bf5716cbc9cabc127046054782 (diff) | |
download | linux-0b5eca67bd2d0e6f6d0ccdc316aced0cc4bf2e9f.tar.xz |
Merge branches 'topic/twl4030' and 'topic/twl6040' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-twl-breakage
Diffstat (limited to 'sound')
165 files changed, 642 insertions, 36611 deletions
diff --git a/sound/Kconfig b/sound/Kconfig index ed34218d38b8..6833db9002ec 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -3,25 +3,7 @@ menuconfig SOUND depends on HAS_IOMEM help If you have a sound card in your computer, i.e. if it can say more - than an occasional beep, say Y. Be sure to have all the information - about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. - - You want to read the Sound-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. General information about - the modular sound system is contained in the files - <file:Documentation/sound/oss/Introduction>. The file - <file:Documentation/sound/oss/README.OSS> contains some slightly - outdated but still useful information as well. Newer sound - driver documentation is found in <file:Documentation/sound/alsa/*>. - - If you have a PnP sound card and you want to configure it at boot - time using the ISA PnP tools (read - <http://www.roestock.demon.co.uk/isapnptools/>), then you need to - compile the sound card support as a module and load that module - after the PnP configuration is finished. To do this, choose M here - and read <file:Documentation/sound/oss/README.modules>; the module - will be called soundcore. + than an occasional beep, say Y. if SOUND @@ -116,19 +98,6 @@ source "sound/synth/Kconfig" endif # SND -menuconfig SOUND_PRIME - tristate "Open Sound System (DEPRECATED)" - select SOUND_OSS_CORE - depends on BROKEN - help - Say 'Y' or 'M' to enable Open Sound System drivers. - -if SOUND_PRIME - -source "sound/oss/Kconfig" - -endif # SOUND_PRIME - endif # !UML endif # SOUND diff --git a/sound/Makefile b/sound/Makefile index f245c75a2add..99d8c31262c8 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -3,8 +3,7 @@ # obj-$(CONFIG_SOUND) += soundcore.o -obj-$(CONFIG_SOUND_PRIME) += oss/ -obj-$(CONFIG_DMASOUND) += oss/ +obj-$(CONFIG_DMASOUND) += oss/dmasound/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ obj-$(CONFIG_SND_AOA) += aoa/ diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index 1ac0c423903e..18cb6f476bf4 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -127,7 +127,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) return 0; } -static struct snd_timer_hardware hrtimer_hw = { +static const struct snd_timer_hardware hrtimer_hw __initconst = { .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET, .open = snd_hrtimer_open, .close = snd_hrtimer_close, @@ -159,6 +159,7 @@ static int __init snd_hrtimer_init(void) timer->hw = hrtimer_hw; timer->hw.resolution = resolution; timer->hw.ticks = NANO_SEC / resolution; + timer->max_instances = 100; /* lower the limit */ err = snd_timer_global_register(timer); if (err < 0) { diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index a73baa1242be..8faae3d1455d 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -228,6 +228,8 @@ static int snd_hwdep_dsp_load(struct snd_hwdep *hw, memset(&info, 0, sizeof(info)); if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; + if (info.index >= 32) + return -EINVAL; /* check whether the dsp was already loaded */ if (hw->dsp_loaded & (1 << info.index)) return -EBUSY; diff --git a/sound/core/init.c b/sound/core/init.c index 32ebe2f6bc59..168ae03d3a1c 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -255,6 +255,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); #endif + init_waitqueue_head(&card->remove_sleep); device_initialize(&card->card_dev); card->card_dev.parent = parent; @@ -452,6 +453,35 @@ int snd_card_disconnect(struct snd_card *card) } EXPORT_SYMBOL(snd_card_disconnect); +/** + * snd_card_disconnect_sync - disconnect card and wait until files get closed + * @card: card object to disconnect + * + * This calls snd_card_disconnect() for disconnecting all belonging components + * and waits until all pending files get closed. + * It assures that all accesses from user-space finished so that the driver + * can release its resources gracefully. + */ +void snd_card_disconnect_sync(struct snd_card *card) +{ + int err; + + err = snd_card_disconnect(card); + if (err < 0) { + dev_err(card->dev, + "snd_card_disconnect error (%d), skipping sync\n", + err); + return; + } + + spin_lock_irq(&card->files_lock); + wait_event_lock_irq(card->remove_sleep, + list_empty(&card->files_list), + card->files_lock); + spin_unlock_irq(&card->files_lock); +} +EXPORT_SYMBOL_GPL(snd_card_disconnect_sync); + static int snd_card_do_free(struct snd_card *card) { #if IS_ENABLED(CONFIG_SND_MIXER_OSS) @@ -957,6 +987,8 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) break; } } + if (list_empty(&card->files_list)) + wake_up_all(&card->remove_sleep); spin_unlock(&card->files_lock); if (!found) { dev_err(card->dev, "card file remove problem (%p)\n", file); diff --git a/sound/core/jack.c b/sound/core/jack.c index f652e90efd7e..84c2a17c56ee 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -310,7 +310,7 @@ EXPORT_SYMBOL(snd_jack_set_parent); * @type: Jack report type for this key * @keytype: Input layer key type to be reported * - * Map a SND_JACK_BTN_ button type to an input layer key, allowing + * Map a SND_JACK_BTN_* button type to an input layer key, allowing * reporting of keys on accessories via the jack abstraction. If no * mapping is provided but keys are enabled in the jack type then * BTN_n numeric buttons will be reported. diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 7eadb7fd8074..9070f277f8db 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -775,6 +775,9 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, .dev_register = snd_pcm_dev_register, .dev_disconnect = snd_pcm_dev_disconnect, }; + static struct snd_device_ops internal_ops = { + .dev_free = snd_pcm_dev_free, + }; if (snd_BUG_ON(!card)) return -ENXIO; @@ -801,7 +804,8 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, if (err < 0) goto free_pcm; - err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops); + err = snd_device_new(card, SNDRV_DEV_PCM, pcm, + internal ? &internal_ops : &ops); if (err < 0) goto free_pcm; @@ -1099,8 +1103,6 @@ static int snd_pcm_dev_register(struct snd_device *device) if (snd_BUG_ON(!device || !device->device_data)) return -ENXIO; pcm = device->device_data; - if (pcm->internal) - return 0; mutex_lock(®ister_mutex); err = snd_pcm_add(pcm); @@ -1152,6 +1154,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { snd_pcm_stream_lock_irq(substream); if (substream->runtime) { + if (snd_pcm_running(substream)) + snd_pcm_stop(substream, + SNDRV_PCM_STATE_DISCONNECTED); + /* to be sure, set the state unconditionally */ substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; wake_up(&substream->runtime->sleep); wake_up(&substream->runtime->tsleep); @@ -1159,12 +1165,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) snd_pcm_stream_unlock_irq(substream); } } - if (!pcm->internal) { - pcm_call_notify(pcm, n_disconnect); - } + + pcm_call_notify(pcm, n_disconnect); for (cidx = 0; cidx < 2; cidx++) { - if (!pcm->internal) - snd_unregister_device(&pcm->streams[cidx].dev); + snd_unregister_device(&pcm->streams[cidx].dev); free_chmap(&pcm->streams[cidx]); } mutex_unlock(&pcm->open_mutex); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a93a4235a332..10e7ef7a8804 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -248,8 +248,10 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream, runtime->rate); *audio_tstamp = ns_to_timespec(audio_nsecs); } - runtime->status->audio_tstamp = *audio_tstamp; - runtime->status->tstamp = *curr_tstamp; + if (!timespec_equal(&runtime->status->audio_tstamp, audio_tstamp)) { + runtime->status->audio_tstamp = *audio_tstamp; + runtime->status->tstamp = *curr_tstamp; + } /* * re-take a driver timestamp to let apps detect if the reference tstamp diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2fec2feac387..a4d92e46c459 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -195,7 +195,6 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) { - struct snd_pcm_runtime *runtime; struct snd_pcm *pcm = substream->pcm; struct snd_pcm_str *pstr = substream->pstr; @@ -211,7 +210,6 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) info->subdevices_count = pstr->substream_count; info->subdevices_avail = pstr->substream_count - pstr->substream_opened; strlcpy(info->subname, substream->name, sizeof(info->subname)); - runtime = substream->runtime; return 0; } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index aaff9ee32695..b30b2139e3f0 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -612,9 +612,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq if (!dp->timer->running) len = snd_seq_oss_timer_start(dp->timer); if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { - if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE) - snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, - ev->data.ext.ptr, ev->data.ext.len); + snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev); } else { len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev); if (len > 0) diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c index 046cb586fb2f..06b21226b4e7 100644 --- a/sound/core/seq/oss/seq_oss_readq.c +++ b/sound/core/seq/oss/seq_oss_readq.c @@ -118,6 +118,35 @@ snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, in } /* + * put MIDI sysex bytes; the event buffer may be chained, thus it has + * to be expanded via snd_seq_dump_var_event(). + */ +struct readq_sysex_ctx { + struct seq_oss_readq *readq; + int dev; +}; + +static int readq_dump_sysex(void *ptr, void *buf, int count) +{ + struct readq_sysex_ctx *ctx = ptr; + + return snd_seq_oss_readq_puts(ctx->readq, ctx->dev, buf, count); +} + +int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev, + struct snd_seq_event *ev) +{ + struct readq_sysex_ctx ctx = { + .readq = q, + .dev = dev + }; + + if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) + return 0; + return snd_seq_dump_var_event(ev, readq_dump_sysex, &ctx); +} + +/* * copy an event to input queue: * return zero if enqueued */ diff --git a/sound/core/seq/oss/seq_oss_readq.h b/sound/core/seq/oss/seq_oss_readq.h index f1463f1f449e..8d033ca2d23f 100644 --- a/sound/core/seq/oss/seq_oss_readq.h +++ b/sound/core/seq/oss/seq_oss_readq.h @@ -44,6 +44,8 @@ void snd_seq_oss_readq_delete(struct seq_oss_readq *q); void snd_seq_oss_readq_clear(struct seq_oss_readq *readq); unsigned int snd_seq_oss_readq_poll(struct seq_oss_readq *readq, struct file *file, poll_table *wait); int snd_seq_oss_readq_puts(struct seq_oss_readq *readq, int dev, unsigned char *data, int len); +int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev, + struct snd_seq_event *ev); int snd_seq_oss_readq_put_event(struct seq_oss_readq *readq, union evrec *ev); int snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *readq, unsigned long curt, int seq_mode); int snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec); diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index d10c780dfd54..6e22eea72654 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -802,6 +802,10 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e return -EMLINK; } + if (snd_seq_ev_is_variable(event) && + snd_BUG_ON(atomic && (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR))) + return -EINVAL; + if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS || event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) result = deliver_to_subscribers(client, event, atomic, hop); diff --git a/sound/core/timer.c b/sound/core/timer.c index 6cdd04a45962..ee09dace8bb1 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -180,7 +180,7 @@ static void snd_timer_request(struct snd_timer_id *tid) * * call this with register_mutex down. */ -static void snd_timer_check_slave(struct snd_timer_instance *slave) +static int snd_timer_check_slave(struct snd_timer_instance *slave) { struct snd_timer *timer; struct snd_timer_instance *master; @@ -190,16 +190,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) list_for_each_entry(master, &timer->open_list_head, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { + if (master->timer->num_instances >= + master->timer->max_instances) + return -EBUSY; list_move_tail(&slave->open_list, &master->slave_list_head); + master->timer->num_instances++; spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; spin_unlock_irq(&slave_active_lock); - return; + return 0; } } } + return 0; } /* @@ -208,7 +213,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) * * call this with register_mutex down. */ -static void snd_timer_check_master(struct snd_timer_instance *master) +static int snd_timer_check_master(struct snd_timer_instance *master) { struct snd_timer_instance *slave, *tmp; @@ -216,7 +221,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master) list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { + if (master->timer->num_instances >= + master->timer->max_instances) + return -EBUSY; list_move_tail(&slave->open_list, &master->slave_list_head); + master->timer->num_instances++; spin_lock_irq(&slave_active_lock); spin_lock(&master->timer->lock); slave->master = master; @@ -228,8 +237,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master) spin_unlock_irq(&slave_active_lock); } } + return 0; } +static int snd_timer_close_locked(struct snd_timer_instance *timeri); + /* * open a timer instance * when opening a master, the slave id must be here given. @@ -240,6 +252,7 @@ int snd_timer_open(struct snd_timer_instance **ti, { struct snd_timer *timer; struct snd_timer_instance *timeri = NULL; + int err; if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { /* open a slave instance */ @@ -259,10 +272,14 @@ int snd_timer_open(struct snd_timer_instance **ti, timeri->slave_id = tid->device; timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; list_add_tail(&timeri->open_list, &snd_timer_slave_list); - snd_timer_check_slave(timeri); + err = snd_timer_check_slave(timeri); + if (err < 0) { + snd_timer_close_locked(timeri); + timeri = NULL; + } mutex_unlock(®ister_mutex); *ti = timeri; - return 0; + return err; } /* open a master instance */ @@ -288,6 +305,10 @@ int snd_timer_open(struct snd_timer_instance **ti, return -EBUSY; } } + if (timer->num_instances >= timer->max_instances) { + mutex_unlock(®ister_mutex); + return -EBUSY; + } timeri = snd_timer_instance_new(owner, timer); if (!timeri) { mutex_unlock(®ister_mutex); @@ -314,25 +335,27 @@ int snd_timer_open(struct snd_timer_instance **ti, } list_add_tail(&timeri->open_list, &timer->open_list_head); - snd_timer_check_master(timeri); + timer->num_instances++; + err = snd_timer_check_master(timeri); + if (err < 0) { + snd_timer_close_locked(timeri); + timeri = NULL; + } mutex_unlock(®ister_mutex); *ti = timeri; - return 0; + return err; } EXPORT_SYMBOL(snd_timer_open); /* * close a timer instance + * call this with register_mutex down. */ -int snd_timer_close(struct snd_timer_instance *timeri) +static int snd_timer_close_locked(struct snd_timer_instance *timeri) { struct snd_timer *timer = NULL; struct snd_timer_instance *slave, *tmp; - if (snd_BUG_ON(!timeri)) - return -ENXIO; - - mutex_lock(®ister_mutex); list_del(&timeri->open_list); /* force to stop the timer */ @@ -340,6 +363,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) timer = timeri->timer; if (timer) { + timer->num_instances--; /* wait, until the active callback is finished */ spin_lock_irq(&timer->lock); while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { @@ -355,6 +379,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { list_move_tail(&slave->open_list, &snd_timer_slave_list); + timer->num_instances--; slave->master = NULL; slave->timer = NULL; list_del_init(&slave->ack_list); @@ -382,9 +407,24 @@ int snd_timer_close(struct snd_timer_instance *timeri) module_put(timer->module); } - mutex_unlock(®ister_mutex); return 0; } + +/* + * close a timer instance + */ +int snd_timer_close(struct snd_timer_instance *timeri) +{ + int err; + + if (snd_BUG_ON(!timeri)) + return -ENXIO; + + mutex_lock(®ister_mutex); + err = snd_timer_close_locked(timeri); + mutex_unlock(®ister_mutex); + return err; +} EXPORT_SYMBOL(snd_timer_close); unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) @@ -856,6 +896,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, spin_lock_init(&timer->lock); tasklet_init(&timer->task_queue, snd_timer_tasklet, (unsigned long)timer); + timer->max_instances = 1000; /* default limit per timer */ if (card != NULL) { timer->module = card->module; err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); @@ -1028,15 +1069,17 @@ EXPORT_SYMBOL(snd_timer_global_register); struct snd_timer_system_private { struct timer_list tlist; + struct snd_timer *snd_timer; unsigned long last_expires; unsigned long last_jiffies; unsigned long correction; }; -static void snd_timer_s_function(unsigned long data) +static void snd_timer_s_function(struct timer_list *t) { - struct snd_timer *timer = (struct snd_timer *)data; - struct snd_timer_system_private *priv = timer->private_data; + struct snd_timer_system_private *priv = from_timer(priv, t, + tlist); + struct snd_timer *timer = priv->snd_timer; unsigned long jiff = jiffies; if (time_after(jiff, priv->last_expires)) priv->correction += (long)jiff - (long)priv->last_expires; @@ -1118,7 +1161,8 @@ static int snd_timer_register_system(void) snd_timer_free(timer); return -ENOMEM; } - setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer); + priv->snd_timer = timer; + timer_setup(&priv->tlist, snd_timer_s_function, 0); timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer); diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 59127b6ef39e..e00f7e399e46 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -66,11 +66,11 @@ static int snd_timer_user_info_compat(struct file *file, struct snd_timer *t; tu = file->private_data; - if (snd_BUG_ON(!tu->timeri)) - return -ENXIO; + if (!tu->timeri) + return -EBADFD; t = tu->timeri->timer; - if (snd_BUG_ON(!t)) - return -ENXIO; + if (!t) + return -EBADFD; memset(&info, 0, sizeof(info)); info.card = t->card ? t->card->number : -1; if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) @@ -99,8 +99,8 @@ static int snd_timer_user_status_compat(struct file *file, struct snd_timer_status32 status; tu = file->private_data; - if (snd_BUG_ON(!tu->timeri)) - return -ENXIO; + if (!tu->timeri) + return -EBADFD; memset(&status, 0, sizeof(status)); status.tstamp.tv_sec = tu->tstamp.tv_sec; status.tstamp.tv_nsec = tu->tstamp.tv_nsec; diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index e43af18d4383..8632301489fa 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -495,7 +495,9 @@ EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster); * Returns 0 if successful, or a negative error code. */ int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl, - int (*func)(struct snd_kcontrol *, void *), + int (*func)(struct snd_kcontrol *vslave, + struct snd_kcontrol *slave, + void *arg), void *arg) { struct link_master *master; @@ -507,7 +509,7 @@ int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl, if (err < 0) return err; list_for_each_entry(slave, &master->slaves, list) { - err = func(&slave->slave, arg); + err = func(slave->kctl, &slave->slave, arg); if (err < 0) return err; } diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 135adb17703c..afac886ffa28 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -529,9 +529,9 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) return running; } -static void loopback_timer_function(unsigned long data) +static void loopback_timer_function(struct timer_list *t) { - struct loopback_pcm *dpcm = (struct loopback_pcm *)data; + struct loopback_pcm *dpcm = from_timer(dpcm, t, timer); unsigned long flags; spin_lock_irqsave(&dpcm->cable->lock, flags); @@ -675,8 +675,7 @@ static int loopback_open(struct snd_pcm_substream *substream) } dpcm->loopback = loopback; dpcm->substream = substream; - setup_timer(&dpcm->timer, loopback_timer_function, - (unsigned long)dpcm); + timer_setup(&dpcm->timer, loopback_timer_function, 0); cable = loopback->cables[substream->number][dev]; if (!cable) { diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index c0939a0164a6..7b2b1f766b00 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -306,9 +306,9 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) return 0; } -static void dummy_systimer_callback(unsigned long data) +static void dummy_systimer_callback(struct timer_list *t) { - struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data; + struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer); unsigned long flags; int elapsed = 0; @@ -343,8 +343,7 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream) if (!dpcm) return -ENOMEM; substream->runtime->private_data = dpcm; - setup_timer(&dpcm->timer, dummy_systimer_callback, - (unsigned long) dpcm); + timer_setup(&dpcm->timer, dummy_systimer_callback, 0); spin_lock_init(&dpcm->lock); dpcm->substream = substream; return 0; diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index b997222274bd..3e745f47dd2f 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -169,9 +169,9 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); * timer callback * reprogram the timer and call the interrupt job */ -static void snd_mpu401_uart_timer(unsigned long data) +static void snd_mpu401_uart_timer(struct timer_list *t) { - struct snd_mpu401 *mpu = (struct snd_mpu401 *)data; + struct snd_mpu401 *mpu = from_timer(mpu, t, timer); unsigned long flags; spin_lock_irqsave(&mpu->timer_lock, flags); @@ -191,8 +191,7 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) spin_lock_irqsave (&mpu->timer_lock, flags); if (mpu->timer_invoked == 0) { - setup_timer(&mpu->timer, snd_mpu401_uart_timer, - (unsigned long)mpu); + timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0); mod_timer(&mpu->timer, 1 + jiffies); } mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 0f6392001e30..547662e02fcc 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -406,10 +406,10 @@ static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int * timer interrupt for outputs */ -static void snd_mtpav_output_timer(unsigned long data) +static void snd_mtpav_output_timer(struct timer_list *t) { unsigned long flags; - struct mtpav *chip = (struct mtpav *)data; + struct mtpav *chip = from_timer(chip, t, timer); int p; spin_lock_irqsave(&chip->spinlock, flags); @@ -707,8 +707,7 @@ static int snd_mtpav_probe(struct platform_device *dev) mtp_card->share_irq = 0; mtp_card->inmidistate = 0; mtp_card->outmidihwport = 0xffffffff; - setup_timer(&mtp_card->timer, snd_mtpav_output_timer, - (unsigned long) mtp_card); + timer_setup(&mtp_card->timer, snd_mtpav_output_timer, 0); card->private_free = snd_mtpav_free; diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index 13c0a7e1bc2b..bb3f3a5a6951 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -238,10 +238,10 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op, /* * System timer interrupt function */ -void snd_opl3_timer_func(unsigned long data) +void snd_opl3_timer_func(struct timer_list *t) { - struct snd_opl3 *opl3 = (struct snd_opl3 *)data; + struct snd_opl3 *opl3 = from_timer(opl3, t, tlist); unsigned long flags; int again = 0; int i; diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index d3e91be8b23a..5f881c4cdf1f 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -248,7 +248,7 @@ static int snd_opl3_seq_probe(struct device *_dev) } /* setup system timer */ - setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3); + timer_setup(&opl3->tlist, snd_opl3_timer_func, 0); spin_lock_init(&opl3->sys_timer_lock); opl3->sys_timer_status = 0; diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h index eaef435e0528..a2445163008e 100644 --- a/sound/drivers/opl3/opl3_voice.h +++ b/sound/drivers/opl3/opl3_voice.h @@ -37,7 +37,7 @@ void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan, struct snd_midi_chann void snd_opl3_sysex(void *p, unsigned char *buf, int len, int parsed, struct snd_midi_channel_set *chset); void snd_opl3_calc_volume(unsigned char *reg, int vel, struct snd_midi_channel *chan); -void snd_opl3_timer_func(unsigned long data); +void snd_opl3_timer_func(struct timer_list *t); /* Prototypes for opl3_drums.c */ void snd_opl3_load_drums(struct snd_opl3 *opl3); diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 88e66ea0306d..0a67b8b9f176 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -309,12 +309,12 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id) } /* When the polling mode, this function calls snd_uart16550_io_loop. */ -static void snd_uart16550_buffer_timer(unsigned long data) +static void snd_uart16550_buffer_timer(struct timer_list *t) { unsigned long flags; struct snd_uart16550 *uart; - uart = (struct snd_uart16550 *)data; + uart = from_timer(uart, t, buffer_timer); spin_lock_irqsave(&uart->open_lock, flags); snd_uart16550_del_timer(uart); snd_uart16550_io_loop(uart); @@ -828,8 +828,7 @@ static int snd_uart16550_create(struct snd_card *card, uart->prev_in = 0; uart->rstatus = 0; memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS); - setup_timer(&uart->buffer_timer, snd_uart16550_buffer_timer, - (unsigned long)uart); + timer_setup(&uart->buffer_timer, snd_uart16550_buffer_timer, 0); uart->timer_running = 0; /* Register device */ diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 23ccddb20de1..4210e5c6262e 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -247,7 +247,7 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, struct amdtp_am824 *p = s->protocol; if (port < p->midi_ports) - ACCESS_ONCE(p->midi[port]) = midi; + WRITE_ONCE(p->midi[port], midi); } EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger); @@ -336,7 +336,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffe unsigned int data_blocks, unsigned int *syt) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { @@ -357,7 +357,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffe unsigned int data_blocks, unsigned int *syt) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 3fc581a5ad62..4a1dc145327b 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -376,7 +376,7 @@ static void update_pcm_pointers(struct amdtp_stream *s, ptr = s->pcm_buffer_pointer + frames; if (ptr >= pcm->runtime->buffer_size) ptr -= pcm->runtime->buffer_size; - ACCESS_ONCE(s->pcm_buffer_pointer) = ptr; + WRITE_ONCE(s->pcm_buffer_pointer, ptr); s->pcm_period_pointer += frames; if (s->pcm_period_pointer >= pcm->runtime->period_size) { @@ -388,7 +388,7 @@ static void update_pcm_pointers(struct amdtp_stream *s, static void pcm_period_tasklet(unsigned long data) { struct amdtp_stream *s = (void *)data; - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); if (pcm) snd_pcm_period_elapsed(pcm); @@ -453,7 +453,7 @@ static int handle_out_packet(struct amdtp_stream *s, s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; - buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | + buffer[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) | s->data_block_counter); @@ -472,7 +472,7 @@ static int handle_out_packet(struct amdtp_stream *s, if (queue_out_packet(s, payload_length) < 0) return -EIO; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); @@ -504,7 +504,7 @@ static int handle_out_packet_without_header(struct amdtp_stream *s, if (queue_out_packet(s, payload_length) < 0) return -EIO; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); @@ -621,7 +621,7 @@ end: if (queue_in_packet(s) < 0) return -EIO; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); @@ -649,7 +649,7 @@ static int handle_in_packet_without_header(struct amdtp_stream *s, if (queue_in_packet(s) < 0) return -EIO; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); @@ -947,7 +947,7 @@ unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s) if (!in_interrupt() && amdtp_stream_running(s)) fw_iso_context_flush_completions(s->context); - return ACCESS_ONCE(s->pcm_buffer_pointer); + return READ_ONCE(s->pcm_buffer_pointer); } EXPORT_SYMBOL(amdtp_stream_pcm_pointer); @@ -977,9 +977,8 @@ EXPORT_SYMBOL(amdtp_stream_pcm_ack); void amdtp_stream_update(struct amdtp_stream *s) { /* Precomputing. */ - ACCESS_ONCE(s->source_node_id_field) = - (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) & - CIP_SID_MASK; + WRITE_ONCE(s->source_node_id_field, + (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) & CIP_SID_MASK); } EXPORT_SYMBOL(amdtp_stream_update); @@ -1022,7 +1021,7 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s) { struct snd_pcm_substream *pcm; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm) snd_pcm_stop_xrun(pcm); } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index a608dae83348..e45de3eecfe3 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -221,7 +221,7 @@ static inline bool amdtp_stream_pcm_running(struct amdtp_stream *s) static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s, struct snd_pcm_substream *pcm) { - ACCESS_ONCE(s->pcm) = pcm; + WRITE_ONCE(s->pcm, pcm); } static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index 1453c34ce99f..4a884a335248 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -327,7 +327,7 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, struct amdtp_dot *p = s->protocol; if (port < MAX_MIDI_PORTS) - ACCESS_ONCE(p->midi[port]) = midi; + WRITE_ONCE(p->midi[port], midi); } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, @@ -338,7 +338,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, struct snd_pcm_substream *pcm; unsigned int pcm_frames; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm) { read_pcm_s32(s, pcm, buffer, data_blocks); pcm_frames = data_blocks; @@ -359,7 +359,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, struct snd_pcm_substream *pcm; unsigned int pcm_frames; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm) { write_pcm_s32(s, pcm, buffer, data_blocks); pcm_frames = data_blocks; diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index 780da9deb2f0..77c7598b61ab 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -108,7 +108,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, unsigned int data_blocks, unsigned int *syt) { - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { @@ -127,7 +127,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, unsigned int data_blocks, unsigned int *syt) { - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c index 949ee56b4e0e..6a49611ee462 100644 --- a/sound/firewire/fireface/ff-midi.c +++ b/sound/firewire/fireface/ff-midi.c @@ -22,7 +22,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) ff->running_status[substream->number] = 0; ff->rx_midi_error[substream->number] = false; - ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = substream; + WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream); return 0; } @@ -38,7 +38,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) struct snd_ff *ff = substream->rmidi->private_data; cancel_work_sync(&ff->rx_midi_work[substream->number]); - ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = NULL; + WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL); return 0; } @@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substream, spin_lock_irqsave(&ff->lock, flags); if (up) - ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = - substream; + WRITE_ONCE(ff->tx_midi_substreams[substream->number], + substream); else - ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = NULL; + WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL); spin_unlock_irqrestore(&ff->lock, flags); } diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index dd6c8e839647..332b29f8ed75 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -12,7 +12,7 @@ static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, int rcode) { struct snd_rawmidi_substream *substream = - ACCESS_ONCE(ff->rx_midi_substreams[port]); + READ_ONCE(ff->rx_midi_substreams[port]); if (rcode_is_permanent_error(rcode)) { ff->rx_midi_error[port] = true; @@ -60,7 +60,7 @@ static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port, static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) { struct snd_rawmidi_substream *substream = - ACCESS_ONCE(ff->rx_midi_substreams[port]); + READ_ONCE(ff->rx_midi_substreams[port]); u8 *buf = (u8 *)ff->msg_buf[port]; int i, len; @@ -159,7 +159,7 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request, */ index = (quad >> 8) & 0xff; if (index > 0) { - substream = ACCESS_ONCE(ff->tx_midi_substreams[0]); + substream = READ_ONCE(ff->tx_midi_substreams[0]); if (substream != NULL) { byte = quad & 0xff; snd_rawmidi_receive(substream, &byte, 1); @@ -169,7 +169,7 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request, /* Message in second port. */ index = (quad >> 24) & 0xff; if (index > 0) { - substream = ACCESS_ONCE(ff->tx_midi_substreams[1]); + substream = READ_ONCE(ff->tx_midi_substreams[1]); if (substream != NULL) { byte = (quad >> 16) & 0xff; snd_rawmidi_receive(substream, &byte, 1); diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 5826aa8362f1..46092fa3ff9b 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -96,7 +96,7 @@ static void isight_update_pointers(struct isight *isight, unsigned int count) ptr += count; if (ptr >= runtime->buffer_size) ptr -= runtime->buffer_size; - ACCESS_ONCE(isight->buffer_pointer) = ptr; + WRITE_ONCE(isight->buffer_pointer, ptr); isight->period_counter += count; if (isight->period_counter >= runtime->period_size) { @@ -111,7 +111,7 @@ static void isight_samples(struct isight *isight, struct snd_pcm_runtime *runtime; unsigned int count1; - if (!ACCESS_ONCE(isight->pcm_running)) + if (!READ_ONCE(isight->pcm_running)) return; runtime = isight->pcm->runtime; @@ -131,7 +131,7 @@ static void isight_samples(struct isight *isight, static void isight_pcm_abort(struct isight *isight) { - if (ACCESS_ONCE(isight->pcm_active)) + if (READ_ONCE(isight->pcm_active)) snd_pcm_stop_xrun(isight->pcm); } @@ -141,7 +141,7 @@ static void isight_dropped_samples(struct isight *isight, unsigned int total) u32 dropped; unsigned int count1; - if (!ACCESS_ONCE(isight->pcm_running)) + if (!READ_ONCE(isight->pcm_running)) return; runtime = isight->pcm->runtime; @@ -293,7 +293,7 @@ static int isight_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - ACCESS_ONCE(isight->pcm_active) = true; + WRITE_ONCE(isight->pcm_active, true); return 0; } @@ -331,7 +331,7 @@ static int isight_hw_free(struct snd_pcm_substream *substream) { struct isight *isight = substream->private_data; - ACCESS_ONCE(isight->pcm_active) = false; + WRITE_ONCE(isight->pcm_active, false); mutex_lock(&isight->mutex); isight_stop_streaming(isight); @@ -424,10 +424,10 @@ static int isight_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - ACCESS_ONCE(isight->pcm_running) = true; + WRITE_ONCE(isight->pcm_running, true); break; case SNDRV_PCM_TRIGGER_STOP: - ACCESS_ONCE(isight->pcm_running) = false; + WRITE_ONCE(isight->pcm_running, false); break; default: return -EINVAL; @@ -439,7 +439,7 @@ static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream) { struct isight *isight = substream->private_data; - return ACCESS_ONCE(isight->buffer_pointer); + return READ_ONCE(isight->buffer_pointer); } static int isight_create_pcm(struct isight *isight) diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 96f0091144bb..f0555a24d90e 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -310,7 +310,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, if (p->midi_ports) read_midi_messages(s, buffer, data_blocks); - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (data_blocks > 0 && pcm) read_pcm_s32(s, pcm->runtime, buffer, data_blocks); @@ -374,7 +374,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, if (p->midi_ports) write_midi_messages(s, buffer, data_blocks); - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm) write_pcm_s32(s, pcm->runtime, buffer, data_blocks); else diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 02d595665898..f33497cdc706 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -112,7 +112,7 @@ static void handle_hss(struct fw_card *card, struct fw_request *request, } if (length >= 1) { - stream = ACCESS_ONCE(scs->input); + stream = READ_ONCE(scs->input); if (stream) midi_input_packet(scs, stream, data, length); } @@ -183,7 +183,7 @@ static void scs_output_work(struct work_struct *work) if (scs->transaction_running) return; - stream = ACCESS_ONCE(scs->output); + stream = READ_ONCE(scs->output); if (!stream || scs->error) { scs->output_idle = true; wake_up(&scs->idle_wait); @@ -291,9 +291,9 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) if (up) { scs->input_escape_count = 0; - ACCESS_ONCE(scs->input) = stream; + WRITE_ONCE(scs->input, stream); } else { - ACCESS_ONCE(scs->input) = NULL; + WRITE_ONCE(scs->input, NULL); } } @@ -319,10 +319,10 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) scs->transaction_bytes = 0; scs->error = false; - ACCESS_ONCE(scs->output) = stream; + WRITE_ONCE(scs->output, stream); schedule_work(&scs->work); } else { - ACCESS_ONCE(scs->output) = NULL; + WRITE_ONCE(scs->output, NULL); } } static void midi_playback_drain(struct snd_rawmidi_substream *stream) diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 6aff1fc1c72d..ab482423c165 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -124,7 +124,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, { struct snd_pcm_substream *pcm; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (data_blocks > 0 && pcm) read_pcm_s32(s, pcm, buffer, data_blocks); @@ -143,7 +143,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, /* This field is not used. */ *syt = 0x0000; - pcm = ACCESS_ONCE(s->pcm); + pcm = READ_ONCE(s->pcm); if (pcm) write_pcm_s32(s, pcm, buffer, data_blocks); else diff --git a/sound/firewire/tascam/tascam-transaction.c b/sound/firewire/tascam/tascam-transaction.c index 8967c52f5032..2ad692dd4b13 100644 --- a/sound/firewire/tascam/tascam-transaction.c +++ b/sound/firewire/tascam/tascam-transaction.c @@ -148,7 +148,7 @@ static void async_midi_port_callback(struct fw_card *card, int rcode, void *callback_data) { struct snd_fw_async_midi_port *port = callback_data; - struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); + struct snd_rawmidi_substream *substream = READ_ONCE(port->substream); /* This port is closed. */ if (substream == NULL) @@ -173,7 +173,7 @@ static void midi_port_work(struct work_struct *work) { struct snd_fw_async_midi_port *port = container_of(work, struct snd_fw_async_midi_port, work); - struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream); + struct snd_rawmidi_substream *substream = READ_ONCE(port->substream); int generation; /* Under transacting or error state. */ @@ -282,7 +282,7 @@ static void handle_midi_tx(struct fw_card *card, struct fw_request *request, bytes = 3; } - substream = ACCESS_ONCE(tscm->tx_midi_substreams[port]); + substream = READ_ONCE(tscm->tx_midi_substreams[port]); if (substream != NULL) snd_rawmidi_receive(substream, b + 1, bytes); } diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index f6d2985b2520..560ec0986e1a 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -319,7 +319,8 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus) break; default: - dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); + dev_err(bus->dev, "Unknown capability %d\n", cur_cap); + cur_cap = 0; break; } diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 19deb306facb..06f845e293cb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -87,7 +87,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, fg = codec->afg ? codec->afg : codec->mfg; - err = snd_hdac_refresh_widgets(codec); + err = snd_hdac_refresh_widgets(codec, false); if (err < 0) goto error; @@ -388,11 +388,12 @@ static void setup_fg_nodes(struct hdac_device *codec) /** * snd_hdac_refresh_widgets - Reset the widget start/end nodes * @codec: the codec object + * @sysfs: re-initialize sysfs tree, too */ -int snd_hdac_refresh_widgets(struct hdac_device *codec) +int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs) { hda_nid_t start_nid; - int nums; + int nums, err; nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); if (!start_nid || nums <= 0 || nums >= 0xff) { @@ -401,6 +402,12 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec) return -EINVAL; } + if (sysfs) { + err = hda_widget_sysfs_reinit(codec, start_nid, nums); + if (err < 0) + return err; + } + codec->num_nodes = nums; codec->start_nid = start_nid; codec->end_nid = start_nid + nums; @@ -408,36 +415,6 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec) } EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); -/** - * snd_hdac_refresh_widget_sysfs - Reset the codec widgets and reinit the - * codec sysfs - * @codec: the codec object - * - * first we need to remove sysfs, then refresh widgets and lastly - * recreate it - */ -int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec) -{ - int ret; - - if (device_is_registered(&codec->dev)) - hda_widget_sysfs_exit(codec); - ret = snd_hdac_refresh_widgets(codec); - if (ret) { - dev_err(&codec->dev, "failed to refresh widget: %d\n", ret); - return ret; - } - if (device_is_registered(&codec->dev)) { - ret = hda_widget_sysfs_init(codec); - if (ret) { - dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); - return ret; - } - } - return ret; -} -EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs); - /* return CONNLIST_LEN parameter of the given widget */ static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) { diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index 3c2d45ee6ab8..fb2aa344981e 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -415,3 +415,50 @@ void hda_widget_sysfs_exit(struct hdac_device *codec) { widget_tree_free(codec); } + +int hda_widget_sysfs_reinit(struct hdac_device *codec, + hda_nid_t start_nid, int num_nodes) +{ + struct hdac_widget_tree *tree; + hda_nid_t end_nid = start_nid + num_nodes; + hda_nid_t nid; + int i; + + if (!codec->widgets) + return hda_widget_sysfs_init(codec); + + tree = kmemdup(codec->widgets, sizeof(*tree), GFP_KERNEL); + if (!tree) + return -ENOMEM; + + tree->nodes = kcalloc(num_nodes + 1, sizeof(*tree->nodes), GFP_KERNEL); + if (!tree->nodes) { + kfree(tree); + return -ENOMEM; + } + + /* prune non-existing nodes */ + for (i = 0, nid = codec->start_nid; i < codec->num_nodes; i++, nid++) { + if (nid < start_nid || nid >= end_nid) + free_widget_node(codec->widgets->nodes[i], + &widget_node_group); + } + + /* add new nodes */ + for (i = 0, nid = start_nid; i < num_nodes; i++, nid++) { + if (nid < codec->start_nid || nid >= codec->end_nid) + add_widget_node(tree->root, nid, &widget_node_group, + &tree->nodes[i]); + else + tree->nodes[i] = + codec->widgets->nodes[nid - codec->start_nid]; + } + + /* replace with the new tree */ + kfree(codec->widgets->nodes); + kfree(codec->widgets); + codec->widgets = tree; + + kobject_uevent(tree->root, KOBJ_CHANGE); + return 0; +} diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index 81acc20c2535..f21633cd9b38 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -746,7 +746,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, memset(pcm_chmap, 0, sizeof(pcm_chmap)); chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap); - for (i = 0; i < sizeof(chmap); i++) + for (i = 0; i < ARRAY_SIZE(pcm_chmap); i++) ucontrol->value.integer.value[i] = pcm_chmap[i]; return 0; diff --git a/sound/hda/local.h b/sound/hda/local.h index 7258fa8ce268..877631e39373 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h @@ -29,6 +29,8 @@ static inline unsigned int get_wcaps_channels(u32 wcaps) extern const struct attribute_group *hdac_dev_attr_groups[]; int hda_widget_sysfs_init(struct hdac_device *codec); +int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid, + int num_nodes); void hda_widget_sysfs_exit(struct hdac_device *codec); #endif /* __HDAC_LOCAL_H */ diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 3ab099fb8c15..b923342cadf4 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -35,7 +35,7 @@ MODULE_LICENSE("GPL"); #define AK4117_ADDR 0x00 /* fixed address */ -static void snd_ak4117_timer(unsigned long data); +static void snd_ak4117_timer(struct timer_list *t); static void reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char val) { @@ -91,7 +91,7 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t chip->read = read; chip->write = write; chip->private_data = private_data; - setup_timer(&chip->timer, snd_ak4117_timer, (unsigned long)chip); + timer_setup(&chip->timer, snd_ak4117_timer, 0); for (reg = 0; reg < 5; reg++) chip->regmap[reg] = pgm[reg]; @@ -529,9 +529,9 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) return res; } -static void snd_ak4117_timer(unsigned long data) +static void snd_ak4117_timer(struct timer_list *t) { - struct ak4117 *chip = (struct ak4117 *)data; + struct ak4117 *chip = from_timer(chip, t, timer); if (chip->init) return; diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 8f34551abd8d..bc5af71d3bdb 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -193,9 +193,9 @@ static inline int emu8k_get_curpos(struct snd_emu8k_pcm *rec, int ch) * timer interrupt handler * check the current position and update the period if necessary. */ -static void emu8k_pcm_timer_func(unsigned long data) +static void emu8k_pcm_timer_func(struct timer_list *t) { - struct snd_emu8k_pcm *rec = (struct snd_emu8k_pcm *)data; + struct snd_emu8k_pcm *rec = from_timer(rec, t, timer); int ptr, delta; spin_lock(&rec->timer_lock); @@ -241,7 +241,7 @@ static int emu8k_pcm_open(struct snd_pcm_substream *subs) runtime->private_data = rec; spin_lock_init(&rec->timer_lock); - setup_timer(&rec->timer, emu8k_pcm_timer_func, (unsigned long)rec); + timer_setup(&rec->timer, emu8k_pcm_timer_func, 0); runtime->hw = emu8k_pcm_hw; runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3; diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index bd672abb4854..4affdcb78f72 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -138,6 +138,7 @@ static int snd_sb8dsp_midi_output_close(struct snd_rawmidi_substream *substream) struct snd_sb *chip; chip = substream->rmidi->private_data; + del_timer_sync(&chip->midi_timer); spin_lock_irqsave(&chip->open_lock, flags); chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER); chip->midi_substream_output = NULL; @@ -209,10 +210,10 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream } } -static void snd_sb8dsp_midi_output_timer(unsigned long data) +static void snd_sb8dsp_midi_output_timer(struct timer_list *t) { - struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *) data; - struct snd_sb * chip = substream->rmidi->private_data; + struct snd_sb *chip = from_timer(chip, t, midi_timer); + struct snd_rawmidi_substream *substream = chip->midi_substream_output; unsigned long flags; spin_lock_irqsave(&chip->open_lock, flags); @@ -230,9 +231,6 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre spin_lock_irqsave(&chip->open_lock, flags); if (up) { if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) { - setup_timer(&chip->midi_timer, - snd_sb8dsp_midi_output_timer, - (unsigned long) substream); mod_timer(&chip->midi_timer, 1 + jiffies); chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER; } @@ -275,6 +273,7 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device) if (chip->hardware >= SB_HW_20) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; + timer_setup(&chip->midi_timer, snd_sb8dsp_midi_output_timer, 0); chip->rmidi = rmidi; return 0; } diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 2aa05f3aaa38..556b14738970 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -349,10 +349,10 @@ static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *subst spin_unlock_irqrestore (&midi->virtual, flags); } -static void snd_wavefront_midi_output_timer(unsigned long data) +static void snd_wavefront_midi_output_timer(struct timer_list *t) { - snd_wavefront_card_t *card = (snd_wavefront_card_t *)data; - snd_wavefront_midi_t *midi = &card->wavefront.midi; + snd_wavefront_midi_t *midi = from_timer(midi, t, timer); + snd_wavefront_card_t *card = midi->timer_card; unsigned long flags; spin_lock_irqsave (&midi->virtual, flags); @@ -383,9 +383,9 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs if (up) { if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { if (!midi->istimer) { - setup_timer(&midi->timer, + timer_setup(&midi->timer, snd_wavefront_midi_output_timer, - (unsigned long) substream->rmidi->card->private_data); + 0); mod_timer(&midi->timer, 1 + jiffies); } midi->istimer++; diff --git a/sound/oss/CHANGELOG b/sound/oss/CHANGELOG deleted file mode 100644 index 8706cd66ca1f..000000000000 --- a/sound/oss/CHANGELOG +++ /dev/null @@ -1,369 +0,0 @@ -Note these changes relate to Hannu's code and don't include the changes -made outside of this for modularising the sound - -Changelog for version 3.8o --------------------------- - -Since 3.8h -- Included support for OPL3-SA1 and SoftOSS - -Since 3.8 -- Fixed SNDCTL_DSP_GETOSPACE -- Compatibility fixes for Linux 2.1.47 - -Since 3.8-beta21 -- Fixed all known bugs (I think). - -Since 3.8-beta8 -- Lot of fixes to audio playback code in dmabuf.c - -Since 3.8-beta6 -- Fixed the famous Quake delay bug. - -Since 3.8-beta5 -- Fixed many bugs in audio playback. - -Since 3.8-beta4 -- Just minor changes. - -Since 3.8-beta1 -- Major rewrite of audio playback handling. -- Added AWE32 support by Takashi Iwai (in ./lowlevel/). - -Since 3.7-beta# -- Passing of ioctl() parameters between soundcard.c and other modules has been -changed so that arg always points to kernel space. -- Some bugfixes. - -Since 3.7-beta5 -- Disabled MIDI input with GUS PnP (Interwave). There seems to be constant -stream of received 0x00 bytes when the MIDI receiver is enabled. - -Since 3.5 -- Changes almost everywhere. -- Support for OPTi 82C924-based sound cards. - -Since 3.5.4-beta8 -- Fixed a bug in handling of non-fragment sized writes in 16 bit/stereo mode - with GUS. -- Limited minimum fragment size with some audio devices (GUS=512 and - SB=32). These devices require more time to "recover" from processing - of each fragment. - -Since 3.5.4-beta6/7 -- There seems to be problems in the OPTi 82C930 so cards based on this - chip don't necessarily work yet. There are problems in detecting the - MIDI interface. Also mixer volumes may be seriously wrong on some systems. - You can safely use this driver version with C930 if it looks to work. - However please don't complain if you have problems with it. C930 support - should be fixed in future releases. -- Got initialization of GUS PnP to work. With this version GUS PnP should - work in GUS compatible mode after initialization using isapnptools. -- Fixed a bug in handling of full duplex cards in write only mode. This has - been causing "audio device opening" errors with RealAudio player. - -Since 3.5.4.beta5 -- Changes to OPTi 82C930 driver. -- Major changes to the Soundscape driver. The driver requires now just one - DMA channel. The extra audio/dsp device (the "Not functional" one) used - for code download in the earlier versions has been eliminated. There is now - just one /dev/dsp# device which is used both for code download and audio. - -Since 3.5.4.beta4 -- Minor changes. - -Since 3.5.4-beta2 -- Fixed silent playback with ESS 688/1688. -- Got SB16 to work without the 16 bit DMA channel (only the 8 bit one - is required for 8 and 16 bit modes). -- Added the "lowlevel" subdirectory for additional low level drivers that - are not part of USS core. See lowlevel/README for more info. -- Included support for ACI mixer (by Markus Kuhn). ACI is a mixer used in - miroPCM sound cards. See lowlevel/aci.readme for more info. -- Support for Aztech Washington chipset (AZT2316 ASIC). - -Since 3.5.4-beta1 -- Reduced clicking with AD1848. -- Support for OPTi 82C930. Only half duplex at this time. 16 bit playback - is sometimes just white noise (occurs randomly). - -Since 3.5.2 -- Major changes to the SB/Jazz16/ESS driver (most parts rewritten). - The most noticeable new feature is support for multiple SB cards at the same - time. -- Renamed sb16_midi.c to uart401.c. Also modified it to work also with - other MPU401 UART compatible cards than SB16/ESS/Jazz. -- Some changes which reduce clicking in audio playback. -- Copying policy is now GPL. - -Since 3.5.1 -- TB Maui initialization support -Since 3.5 -- Improved handling of playback underrun situations. - -Since 3.5-beta10 -- Bug fixing - -Since 3.5-beta9 -- Fixed for compatibility with Linux 1.3.70 and later. -- Changed boot time passing of 16 bit DMA channel number to SB driver. - -Since 3.5-beta8 -- Minor changes - -Since 3.5-beta7 -- enhancements to configure program (by Jeff Tranter): - - prompts are in same format as 1.3.x Linux kernel config program - - on-line help for each question - - fixed some compile warnings detected by gcc/g++ -Wall - - minor grammatical changes to prompts - -Since 3.5-beta6 -- Fixed bugs in mmap() support. -- Minor changes to Maui driver. - -Since 3.5-beta5 -- Fixed crash after recording with ESS688. It's generally a good - idea to stop inbound DMA transfers before freeing the memory - buffer. -- Fixed handling of AD1845 codec (for example Shuttle Sound System). -- Few other fixes. - -Since 3.5-beta4 -- Fixed bug in handling of uninitialized instruments with GUS. - -Since 3.5-beta3 -- Few changes which decrease popping at end/beginning of audio playback. - -Since 3.5-beta2 -- Removed MAD16+CS4231 hack made in previous version since it didn't - help. -- Fixed the above bug in proper way and in proper place. Many thanks - to James Hightower. - -Since 3.5-beta1 -- Bug fixes. -- Full duplex audio with MAD16+CS4231 may work now. The driver configures - SB DMA of MAD16 so that it doesn't conflict with codec's DMA channels. - The side effect is that all 8 bit DMA channels (0,1,3) are populated in - duplex mode. - -Since 3.5-alpha9 -- Bug fixes (mostly in Jazz16 and ESS1688/688 supports). -- Temporarily disabled recording with ESS1688/688 since it causes crash. -- Changed audio buffer partitioning algorithm so that it selects - smaller fragment size than earlier. This improves real time capabilities - of the driver and makes recording to disk to work better. Unfortunately - this change breaks some programs which assume that fragments cannot be - shorter than 4096 bytes. - -Since 3.5-alpha8 -- Bug fixes - -Since 3.5-alpha7 -- Linux kernel compatible configuration (_EXPERIMENTAL_). Enable - using command "cd /linux/drivers/sound;make script" and then - just run kernel's make config normally. -- Minor fixes to the SB support. Hopefully the driver works with - all SB models now. -- Added support for ESS ES1688 "AudioDrive" based cards. - -Since 3.5-alpha6 -- SB Pro and SB16 supports are no longer separately selectable options. - Enabling SB enables them too. -- Changed all #ifndef EXCLUDE_xx stuff to #ifdef CONFIG_xx. Modified -configure to handle this. -- Removed initialization messages from the -modularized version. They can be enabled by using init_trace=1 in -the insmod command line (insmod sound init_trace=1). -- More AIX stuff. -- Added support for synchronizing dsp/audio devices with /dev/sequencer. -- mmap() support for dsp/audio devices. - -Since 3.5-alpha5 -- AIX port. -- Changed some xxx_PATCH macros in soundcard.h to work with - big endian machines. - -Since 3.5-alpha4 -- Removed the 'setfx' stuff from the version distributed with kernel - sources. Running 'setfx' is required again. - -Since 3.5-alpha3 -- Moved stuff from the 'setfx' program to the AudioTrix Pro driver. - -Since 3.5-alpha2 -- Modifications to makefile and configure.c. Unnecessary sources - are no longer compiled. Newly created local.h is also copied to - /etc/soundconf. "make oldconfig" reads /etc/soundconf and produces - new local.h which is compatible with current version of the driver. -- Some fixes to the SB16 support. -- Fixed random protection fault in gus_wave.c - -Since 3.5-alpha1 -- Modified to work with Linux-1.3.33 and later -- Some minor changes - -Since 3.0.2 -- Support for CS4232 based PnP cards (AcerMagic S23 etc). -- Full duplex support for some CS4231, CS4232 and AD1845 based cards -(GUS MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards -having a codec mentioned above). -- Almost fully rewritten loadable modules support. -- Fixed some bugs. -- Huge amount of testing (more testing is still required). -- mmap() support (works with some cards). Requires much more testing. -- Sample/patch/program loading for TB Maui/Tropez. No initialization -since TB doesn't allow me to release that code. -- Using CS4231 compatible codecs as timer for /dev/music. - -Since 3.0.1 -- Added allocation of I/O ports, DMA channels and interrupts -to the initialization code. This may break modules support since -the driver may not free some resources on unload. Should be fixed soon. - -Since 3.0 -- Some important bug fixes. -- select() for /dev/dsp and /dev/audio (Linux only). -(To use select() with read, you have to call read() to start -the recording. Calling write() kills recording immediately so -use select() carefully when you are writing a half duplex app. -Full duplex mode is not implemented yet.) Select works also with -/dev/sequencer and /dev/music. Maybe with /dev/midi## too. - -Since 3.0-beta2 -- Minor fixes. -- Added Readme.cards - -Since 3.0-beta1 -- Minor fixes to the modules support. -- Eliminated call to sb_free_irq() in ad1848.c -- Rewritten MAD16&Mozart support (not tested with MAD16 Pro). -- Fix to DMA initialization of PSS cards. -- Some fixes to ad1848/cs42xx mixer support (GUS MAX, MSS, etc.) -- Fixed some bugs in the PSS driver which caused I/O errors with - the MSS mode (/dev/dsp). - -Since 3.0-950506 -- Recording with GUS MAX fixed. It works when the driver is configured - to use two DMA channels with GUS MAX (16 bit ones recommended). - -Since 3.0-94xxxx -- Too many changes - -Since 3.0-940818 -- Fixes for Linux 1.1.4x. -- Disables Disney Sound System with SG NX Pro 16 (less noise). - -Since 2.90-2 -- Fixes to soundcard.h -- Non blocking mode to /dev/sequencer -- Experimental detection code for Ensoniq Soundscape. - -Since 2.90 -- Minor and major bug fixes - -Since pre-3.0-940712 -- GUS MAX support -- Partially working MSS/WSS support (could work with some cards). -- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs - (GUS MAX, GUS16, WSS etc). Hardware ADPCM is possible with GUS16 and - GUS MAX, but it doesn't work yet. -Since pre-3.0-940426 -- AD1848/CS4248/CS4231 codec support (MSS, GUS MAX, Aztec, Orchid etc). -This codec chip is used in various sound cards. This version is developed -for the 16 bit daughtercard of GUS. It should work with other cards also -if the following requirements are met: - - The I/O, IRQ and DMA settings are jumper selectable or - the card is initialized by booting DOS before booting Linux (etc.). - - You add the IO, IRQ and DMA settings manually to the local.h. - (Just define GUS16_BASE, GUS16_IRQ and GUS16_DMA). Note that - the base address bust be the base address of the codec chip not the - card itself. For the GUS16 these are the same but most MSS compatible - cards have the codec located at card_base+4. -- Some minor changes - -Since 2.5 (******* MAJOR REWRITE ***********) - -This version is based on v2.3. I have tried to maintain two versions -together so that this one should have the same features than v2.5. -Something may still be missing. If you notice such things, please let me -know. - -The Readme.v30 contains more details. - -- /dev/midi## devices. -- /dev/sequencer2 - -Since 2.5-beta2 -- Some fine tuning to the GUS v3.7 mixer code. -- Fixed speed limits for the plain SB (1.0 to 2.0). - -Since 2.5-beta -- Fixed OPL-3 detection with SB. Caused problems with PAS16. -- GUS v3.7 mixer support. - -Since 2.4 -- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h). -- Fixed truncated sound on /dev/dsp when the device is closed. -- Linear volume mode for GUS -- Pitch bends larger than +/- 2 octaves. -- MIDI recording for SB and SB Pro. (Untested). -- Some other fixes. -- SB16 MIDI and DSP drivers only initialized if SB16 actually installed. -- Implemented better detection for OPL-3. This should be useful if you - have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3. -- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested). - -Since 2.3b -- Fixed bug which made it impossible to make long recordings to disk. - Recording was not restarted after a buffer overflow situation. -- Limited mixer support for GUS. -- Numerous improvements to the GUS driver by Andrew Robinson. Including - some click removal etc. - -Since 2.3 -- Fixed some minor bugs in the SB16 driver. - -Since 2.2b -- Full SB16 DSP support. 8/16 bit, mono/stereo -- The SCO and FreeBSD versions should be in sync now. There are some - problems with SB16 and GUS in the FreeBSD versions. - The DMA buffer allocation of the SCO version has been polished but - there could still be some problems. At least it hogs memory. - The DMA channel - configuration method used in the SCO/System is a hack. -- Support for the MPU emulation of the SB16. -- Some big arrays are now allocated boot time. This makes the BSS segment - smaller which makes it possible to use the full driver with - NetBSD. These arrays are not allocated if no suitable sound card is available. -- Fixed a bug in the compute_and_set_volume in gus_wave.c -- Fixed the too fast mono playback problem of SB Pro and PAS16. - -Since 2.2 -- Stereo recording for SB Pro. Somehow it was missing and nobody - had noticed it earlier. -- Minor polishing. -- Interpreting of boot time arguments (sound=) for Linux. -- Breakup of sb_dsp.c. Parts of the code has been moved to - sb_mixer.c and sb_midi.c - -Since 2.1 -- Preliminary support for SB16. - - The SB16 mixer is supported in its native mode. - - Digitized voice capability up to 44.1 kHz/8 bit/mono - (16 bit and stereo support coming in the next release). -- Fixed some bugs in the digitized voice driver for PAS16. -- Proper initialization of the SB emulation of latest PAS16 models. - -- Significantly improved /dev/dsp and /dev/audio support. - - Now supports half duplex mode. It's now possible to record and - playback without closing and reopening the device. - - It's possible to use smaller buffers than earlier. There is a new - ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4. - This call instructs the driver to use smaller buffers. The default - buffer size (0.5 to 1.0 seconds) is divided by n. Should be called - immediately after opening the device. - -Since 2.0 -Just cosmetic changes. diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig deleted file mode 100644 index 4033fe58f0cf..000000000000 --- a/sound/oss/Kconfig +++ /dev/null @@ -1,533 +0,0 @@ -# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net> -# More hacking for modularisation. -# -# Prompt user for primary drivers. - -config SOUND_BCM_CS4297A - tristate "Crystal Sound CS4297a (for Swarm)" - depends on SIBYTE_SWARM - help - The BCM91250A has a Crystal CS4297a on synchronous serial - port B (in addition to the DB-9 serial port). Say Y or M - here to enable the sound chip instead of the UART. Also - note that CONFIG_KGDB should not be enabled at the same - time, since it also attempts to use this UART port. - -config SOUND_MSNDCLAS - tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on (m || !STANDALONE) && ISA - help - Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or - Monterey (not for the Pinnacle or Fiji). - - See <file:Documentation/sound/oss/MultiSound> for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at <http://www.turtlebeach.com/site/kb_ftp/790.asp>. - -comment "Compiled-in MSND Classic support requires firmware during compilation." - depends on SOUND_PRIME && SOUND_MSNDCLAS=y - -config MSNDCLAS_HAVE_BOOT - bool - depends on SOUND_MSNDCLAS=y && !STANDALONE - default y - -config MSNDCLAS_INIT_FILE - string "Full pathname of MSNDINIT.BIN firmware file" - depends on SOUND_MSNDCLAS - default "/etc/sound/msndinit.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDCLAS_PERM_FILE - string "Full pathname of MSNDPERM.BIN firmware file" - depends on SOUND_MSNDCLAS - default "/etc/sound/msndperm.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDCLAS_IRQ - int "MSND Classic IRQ 5, 7, 9, 10, 11, 12" - depends on SOUND_MSNDCLAS=y - default "5" - help - Interrupt Request line for the MultiSound Classic and related cards. - -config MSNDCLAS_MEM - hex "MSND Classic memory B0000, C8000, D0000, D8000, E0000, E8000" - depends on SOUND_MSNDCLAS=y - default "D0000" - help - Memory-mapped I/O base address for the MultiSound Classic and - related cards. - -config MSNDCLAS_IO - hex "MSND Classic I/O 210, 220, 230, 240, 250, 260, 290, 3E0" - depends on SOUND_MSNDCLAS=y - default "290" - help - I/O port address for the MultiSound Classic and related cards. - -config SOUND_MSNDPIN - tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" - depends on (m || !STANDALONE) && ISA - help - Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. - See <file:Documentation/sound/oss/MultiSound> for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at <http://www.turtlebeach.com/site/kb_ftp/600.asp>. - -comment "Compiled-in MSND Pinnacle support requires firmware during compilation." - depends on SOUND_PRIME && SOUND_MSNDPIN=y - -config MSNDPIN_HAVE_BOOT - bool - depends on SOUND_MSNDPIN=y - default y - -config MSNDPIN_INIT_FILE - string "Full pathname of PNDSPINI.BIN firmware file" - depends on SOUND_MSNDPIN - default "/etc/sound/pndspini.bin" - help - The MultiSound cards have two firmware files which are required - for operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDPIN_PERM_FILE - string "Full pathname of PNDSPERM.BIN firmware file" - depends on SOUND_MSNDPIN - default "/etc/sound/pndsperm.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - <file:Documentation/sound/oss/MultiSound> for information on how to - obtain this. - -config MSNDPIN_IRQ - int "MSND Pinnacle IRQ 5, 7, 9, 10, 11, 12" - depends on SOUND_MSNDPIN=y - default "5" - help - Interrupt request line for the primary synthesizer on MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_MEM - hex "MSND Pinnacle memory B0000, C8000, D0000, D8000, E0000, E8000" - depends on SOUND_MSNDPIN=y - default "D0000" - help - Memory-mapped I/O base address for the primary synthesizer on - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_IO - hex "MSND Pinnacle I/O 210, 220, 230, 240, 250, 260, 290, 3E0" - depends on SOUND_MSNDPIN=y - default "290" - help - Memory-mapped I/O base address for the primary synthesizer on - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_DIGITAL - bool "MSND Pinnacle has S/PDIF I/O" - depends on SOUND_MSNDPIN=y - help - If you have the S/PDIF daughter board for the Pinnacle or Fiji, - answer Y here; otherwise, say N. If you have this, you will be able - to play and record from the S/PDIF port (digital signal). See - <file:Documentation/sound/oss/MultiSound> for information on how to make - use of this capability. - -config MSNDPIN_NONPNP - bool "MSND Pinnacle non-PnP Mode" - depends on SOUND_MSNDPIN=y - help - The Pinnacle and Fiji card resources can be configured either with - PnP, or through a configuration port. Say Y here if your card is NOT - in PnP mode. For the Pinnacle, configuration in non-PnP mode allows - use of the IDE and joystick peripherals on the card as well; these - do not show up when the card is in PnP mode. Specifying zero for any - resource of a device will disable the device. If you are running the - card in PnP mode, you must say N here and use isapnptools to - configure the card's resources. - -comment "MSND Pinnacle DSP section will be configured to above parameters." - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP - -config MSNDPIN_CFG - hex "MSND Pinnacle config port 250,260,270" - depends on MSNDPIN_NONPNP - default "250" - help - This is the port which the Pinnacle and Fiji uses to configure the - card's resources when not in PnP mode. If your card is in PnP mode, - then be sure to say N to the previous option, "MSND Pinnacle Non-PnP - Mode". - -comment "Pinnacle-specific Device Configuration (0 disables)" - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP - -config MSNDPIN_MPU_IO - hex "MSND Pinnacle MPU I/O (e.g. 330)" - depends on MSNDPIN_NONPNP - default "0" - help - Memory-mapped I/O base address for the Kurzweil daughterboard - synthesizer on MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_MPU_IRQ - int "MSND Pinnacle MPU IRQ (e.g. 9)" - depends on MSNDPIN_NONPNP - default "0" - help - Interrupt request number for the Kurzweil daughterboard - synthesizer on MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IO0 - hex "MSND Pinnacle IDE I/O 0 (e.g. 170)" - depends on MSNDPIN_NONPNP - default "0" - help - CD-ROM drive 0 memory-mapped I/O base address for the MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IO1 - hex "MSND Pinnacle IDE I/O 1 (e.g. 376)" - depends on MSNDPIN_NONPNP - default "0" - help - CD-ROM drive 1 memory-mapped I/O base address for the MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IRQ - int "MSND Pinnacle IDE IRQ (e.g. 15)" - depends on MSNDPIN_NONPNP - default "0" - help - Interrupt request number for the IDE CD-ROM interface on the - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_JOYSTICK_IO - hex "MSND Pinnacle joystick I/O (e.g. 200)" - depends on MSNDPIN_NONPNP - default "0" - help - Memory-mapped I/O base address for the joystick port on MultiSound - Pinnacle and Fiji sound cards. - -config MSND_FIFOSIZE - int "MSND buffer size (kB)" - depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y - default "128" - help - Configures the size of each audio buffer, in kilobytes, for - recording and playing in the MultiSound drivers (both the Classic - and Pinnacle). Larger values reduce the chance of data overruns at - the expense of overall latency. If unsure, use the default. - -menuconfig SOUND_OSS - tristate "OSS sound modules" - depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER) - depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN - help - OSS is the Open Sound System suite of sound card drivers. They make - sound programming easier since they provide a common API. Say Y or - M here (the module will be called sound) if you haven't found a - driver for your sound card above, then pick your driver from the - list below. - -if SOUND_OSS - -config SOUND_TRACEINIT - bool "Verbose initialisation" - help - Verbose soundcard initialization -- affects the format of autoprobe - and initialization messages at boot time. - -config SOUND_DMAP - bool "Persistent DMA buffers" - ---help--- - Linux can often have problems allocating DMA buffers for ISA sound - cards on machines with more than 16MB of RAM. This is because ISA - DMA buffers must exist below the 16MB boundary and it is quite - possible that a large enough free block in this region cannot be - found after the machine has been running for a while. If you say Y - here the DMA buffers (64Kb) will be allocated at boot time and kept - until the shutdown. This option is only useful if you said Y to - "OSS sound modules", above. If you said M to "OSS sound modules" - then you can get the persistent DMA buffer functionality by passing - the command-line argument "dmabuf=1" to the sound module. - - Say Y unless you have 16MB or more RAM or a PCI sound card. - -config SOUND_VMIDI - tristate "Loopback MIDI device support" - help - Support for MIDI loopback on port 1 or 2. - -config SOUND_TRIX - tristate "MediaTrix AudioTrix Pro support" - help - Answer Y if you have the AudioTriX Pro sound card manufactured - by MediaTrix. - -config TRIX_HAVE_BOOT - bool "Have TRXPRO.HEX firmware file" - depends on SOUND_TRIX=y && !STANDALONE - help - The MediaTrix AudioTrix Pro has an on-board microcontroller which - needs to be initialized by downloading the code from the file - TRXPRO.HEX in the DOS driver directory. If you don't have the - TRXPRO.HEX file handy you may skip this step. However, the SB and - MPU-401 modes of AudioTrix Pro will not work without this file! - -config TRIX_BOOT_FILE - string "Full pathname of TRXPRO.HEX firmware file" - depends on TRIX_HAVE_BOOT - default "/etc/sound/trxpro.hex" - help - Enter the full pathname of your TRXPRO.HEX file, starting from /. - -config SOUND_MSS - tristate "Microsoft Sound System support" - ---help--- - Again think carefully before answering Y to this question. It's - safe to answer Y if you have the original Windows Sound System card - made by Microsoft or Aztech SG 16 Pro (or NX16 Pro). Also you may - say Y in case your card is NOT among these: - - ATI Stereo F/X, AdLib, Audio Excell DSP16, Cardinal DSP16, - Ensoniq SoundScape (and compatibles made by Reveal and Spea), - Gravis Ultrasound, Gravis Ultrasound ACE, Gravis Ultrasound Max, - Gravis Ultrasound with 16 bit option, Logitech Sound Man 16, - Logitech SoundMan Games, Logitech SoundMan Wave, MAD16 Pro (OPTi - 82C929), Media Vision Jazz16, MediaTriX AudioTriX Pro, Microsoft - Windows Sound System (MSS/WSS), Mozart (OAK OTI-601), Orchid - SW32, Personal Sound System (PSS), Pro Audio Spectrum 16, Pro - Audio Studio 16, Pro Sonic 16, Roland MPU-401 MIDI interface, - Sound Blaster 1.0, Sound Blaster 16, Sound Blaster 16ASP, Sound - Blaster 2.0, Sound Blaster AWE32, Sound Blaster Pro, TI TM4000M - notebook, ThunderBoard, Turtle Beach Tropez, Yamaha FM - synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface. - - For cards having native support in VoxWare, consult the card - specific instructions in <file:Documentation/sound/oss/README.OSS>. - Some drivers have their own MSS support and saying Y to this option - will cause a conflict. - - If you compile the driver into the kernel, you have to add - "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command - line. - -config SOUND_MPU401 - tristate "MPU-401 support (NOT for SB16)" - ---help--- - Be careful with this question. The MPU401 interface is supported by - all sound cards. However, some natively supported cards have their - own driver for MPU401. Enabling this MPU401 option with these cards - will cause a conflict. Also, enabling MPU401 on a system that - doesn't really have a MPU401 could cause some trouble. If your card - was in the list of supported cards, look at the card specific - instructions in the <file:Documentation/sound/oss/README.OSS> file. It - is safe to answer Y if you have a true MPU401 MIDI interface card. - - If you compile the driver into the kernel, you have to add - "mpu401=<io>,<irq>" to the kernel command line. - -config SOUND_PAS - tristate "ProAudioSpectrum 16 support" - ---help--- - Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio - 16 or Logitech SoundMan 16 sound card. Answer N if you have some - other card made by Media Vision or Logitech since those are not - PAS16 compatible. Please read <file:Documentation/sound/oss/PAS16>. - It is not necessary to add Sound Blaster support separately; it - is included in PAS support. - - If you compile the driver into the kernel, you have to add - "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2> - to the kernel command line. - -config PAS_JOYSTICK - bool "Enable PAS16 joystick port" - depends on SOUND_PAS=y - help - Say Y here to enable the Pro Audio Spectrum 16's auxiliary joystick - port. - -config SOUND_PSS - tristate "PSS (AD1848, ADSP-2115, ESC614) support" - help - Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven - ADSP-16 or some other card based on the PSS chipset (AD1848 codec + - ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on - how to compile it into the kernel or as a module see the file - <file:Documentation/sound/oss/PSS>. - - If you compile the driver into the kernel, you have to add - "pss=<io>,<mssio>,<mssirq>,<mssdma>,<mpuio>,<mpuirq>" to the kernel - command line. - -config PSS_MIXER - bool "Enable PSS mixer (Beethoven ADSP-16 and other compatible)" - depends on SOUND_PSS - help - Answer Y for Beethoven ADSP-16. You may try to say Y also for other - cards if they have master volume, bass, treble, and you can't - control it under Linux. If you answer N for Beethoven ADSP-16, you - can't control master volume, bass, treble and synth volume. - - If you said M to "PSS support" above, you may enable or disable this - PSS mixer with the module parameter pss_mixer. For more information - see the file <file:Documentation/sound/oss/PSS>. - -config PSS_HAVE_BOOT - bool "Have DSPxxx.LD firmware file" - depends on SOUND_PSS && !STANDALONE - help - If you have the DSPxxx.LD file or SYNTH.LD file for you card, say Y - to include this file. Without this file the synth device (OPL) may - not work. - -config PSS_BOOT_FILE - string "Full pathname of DSPxxx.LD firmware file" - depends on PSS_HAVE_BOOT - default "/etc/sound/dsp001.ld" - help - Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file, - starting from /. - -config SOUND_SB - tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" - ---help--- - Answer Y if you have an original Sound Blaster card made by Creative - Labs or a 100% hardware compatible clone (like the Thunderboard or - SM Games). For an unknown card you may answer Y if the card claims - to be Sound Blaster-compatible. - - Please read the file <file:Documentation/sound/oss/Soundblaster>. - - You should also say Y here for cards based on the Avance Logic - ALS-007 and ALS-1X0 chips (read <file:Documentation/sound/oss/ALS>) and - for cards based on ESS chips (read - <file:Documentation/sound/oss/ESS1868> and - <file:Documentation/sound/oss/ESS>). If you have an IBM Mwave - card, say Y here and read <file:Documentation/sound/oss/mwave>. - - If you compile the driver into the kernel and don't want to use - isapnp, you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel - command line. - - You can say M here to compile this driver as a module; the module is - called sb. - -config SOUND_YM3812 - tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" - ---help--- - Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - Answering Y is usually a safe and recommended choice, however some - cards may have software (TSR) FM emulation. Enabling FM support with - these cards may cause trouble (I don't currently know of any such - cards, however). Please read the file - <file:Documentation/sound/oss/OPL3> if your card has an OPL3 chip. - - If you compile the driver into the kernel, you have to add - "opl3=<io>" to the kernel command line. - - If unsure, say Y. - -config SOUND_UART6850 - tristate "6850 UART support" - help - This option enables support for MIDI interfaces based on the 6850 - UART chip. This interface is rarely found on sound cards. It's safe - to answer N to this question. - - If you compile the driver into the kernel, you have to add - "uart6850=<io>,<irq>" to the kernel command line. - -config SOUND_AEDSP16 - tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" - ---help--- - Answer Y if you have a Gallant's Audio Excel DSP 16 card. This - driver supports Audio Excel DSP 16 but not the III nor PnP versions - of this card. - - The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or - a Microsoft Sound System card, so you should have said Y to either - "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" - or "Microsoft Sound System support", above, and you need to answer - the "MSS emulation" and "SBPro emulation" questions below - accordingly. You should say Y to one and only one of these two - questions. - - Read the <file:Documentation/sound/oss/README.OSS> file and the head of - <file:sound/oss/aedsp16.c> as well as - <file:Documentation/sound/oss/AudioExcelDSP16> to get more information - about this driver and its configuration. - -config SC6600 - bool "SC-6600 based audio cards (new Audio Excel DSP 16)" - depends on SOUND_AEDSP16 - help - The SC6600 is the new version of DSP mounted on the Audio Excel DSP - 16 cards. Find in the manual the FCC ID of your audio card and - answer Y if you have an SC6600 DSP. - -config SC6600_JOY - bool "Activate SC-6600 Joystick Interface" - depends on SC6600 - help - Say Y here in order to use the joystick interface of the Audio Excel - DSP 16 card. - -config SC6600_CDROM - int "SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)" - depends on SC6600 - default "4" - help - This is used to activate the CD-ROM interface of the Audio Excel - DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no - CD-ROM present. - -config SC6600_CDROMBASE - hex "SC-6600 CDROM Interface I/O Address" - depends on SC6600 - default "0" - help - Base I/O port address for the CD-ROM interface of the Audio Excel - DSP 16 card. - -config SOUND_VIDC - tristate "VIDC 16-bit sound" - depends on ARM && ARCH_ACORN - help - 16-bit support for the VIDC onboard sound hardware found on Acorn - machines. - -config SOUND_WAVEARTIST - tristate "Netwinder WaveArtist" - depends on ARM && ARCH_NETWINDER - help - Say Y here to include support for the Rockwell WaveArtist sound - system. This driver is mainly for the NetWinder. - -config SOUND_KAHLUA - tristate "XpressAudio Sound Blaster emulation" - depends on SOUND_SB - -endif # SOUND_OSS - diff --git a/sound/oss/Makefile b/sound/oss/Makefile deleted file mode 100644 index 6564eace4749..000000000000 --- a/sound/oss/Makefile +++ /dev/null @@ -1,108 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the Linux sound card driver -# -# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net> -# Rewritten to use lists instead of if-statements. - -# Each configuration option enables a list of files. - -obj-$(CONFIG_SOUND_OSS) += sound.o - -# Please leave it as is, cause the link order is significant ! - -obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o -obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o -obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_MSS) += ad1848.o -obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o -obj-$(CONFIG_SOUND_MPU401) += mpu401.o -obj-$(CONFIG_SOUND_UART6850) += uart6850.o -obj-$(CONFIG_SOUND_YM3812) += opl3.o -obj-$(CONFIG_SOUND_VMIDI) += v_midi.o -obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o -obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o -obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o -obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o -obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o - -obj-$(CONFIG_DMASOUND) += dmasound/ - -# Declare multi-part drivers. - -sound-objs := \ - dev_table.o soundcard.o \ - audio.o dmabuf.o \ - midi_synth.o midibuf.o \ - sequencer.o sound_timer.o sys_timer.o - -pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o -sb-objs := sb_card.o -sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o -vidc_mod-objs := vidc.o vidc_fill.o - -hostprogs-y := bin2hex hex2hex - -# Files generated that shall be removed upon make clean -clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \ - pss_boot.h trix_boot.h - -# Firmware files that need translation -# -# The translated files are protected by a file that keeps track -# of what name was used to build them. If the name changes, they -# will be forced to be remade. -# - -# Turtle Beach MultiSound - -ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y) - $(obj)/msnd_classic.o: $(obj)/msndperm.c $(obj)/msndinit.c - - $(obj)/msndperm.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_PERM_FILE)) $(obj)/bin2hex - $(obj)/bin2hex msndperm < $< > $@ - - $(obj)/msndinit.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_INIT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex msndinit < $< > $@ -endif - -ifeq ($(CONFIG_MSNDPIN_HAVE_BOOT),y) - $(obj)/msnd_pinnacle.o: $(obj)/pndsperm.c $(obj)/pndspini.c - - $(obj)/pndsperm.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_PERM_FILE)) $(obj)/bin2hex - $(obj)/bin2hex pndsperm < $< > $@ - - $(obj)/pndspini.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_INIT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex pndspini < $< > $@ -endif - -# PSS (ECHO-ADI2111) - -$(obj)/pss.o: $(obj)/pss_boot.h - -ifeq ($(CONFIG_PSS_HAVE_BOOT),y) - $(obj)/pss_boot.h: $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE)) $(obj)/bin2hex - $(obj)/bin2hex pss_synth < $< > $@ -else - $(obj)/pss_boot.h: - $(Q)( \ - echo 'static unsigned char * pss_synth = NULL;'; \ - echo 'static int pss_synthLen = 0;'; \ - ) > $@ -endif - -# MediaTrix AudioTrix Pro - -$(obj)/trix.o: $(obj)/trix_boot.h - -ifeq ($(CONFIG_TRIX_HAVE_BOOT),y) - $(obj)/trix_boot.h: $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) $(obj)/hex2hex - $(obj)/hex2hex -i trix_boot < $< > $@ -else - $(obj)/trix_boot.h: - $(Q)( \ - echo 'static unsigned char * trix_boot = NULL;'; \ - echo 'static int trix_boot_len = 0;'; \ - ) > $@ -endif diff --git a/sound/oss/README.FIRST b/sound/oss/README.FIRST deleted file mode 100644 index 90fdcf063d2d..000000000000 --- a/sound/oss/README.FIRST +++ /dev/null @@ -1,6 +0,0 @@ -The modular sound driver patches were funded by Red Hat Software -(www.redhat.com). The sound driver here is thus a modified version of -Hannu's code. Please bear that in mind when considering the appropriate -forums for bug reporting. - -Alan Cox diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c deleted file mode 100644 index 2421f59cf279..000000000000 --- a/sound/oss/ad1848.c +++ /dev/null @@ -1,3062 +0,0 @@ -/* - * sound/oss/ad1848.c - * - * The low level driver for the AD1848/CS4248 codec chip which - * is used for example in the MS Sound System. - * - * The CS4231 which is used in the GUS MAX and some other cards is - * upwards compatible with AD1848 and this driver is able to drive it. - * - * CS4231A and AD1845 are upward compatible with CS4231. However - * the new features of these chips are different. - * - * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). - * CS4232A is an improved version of CS4232. - * - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * general sleep/wakeup clean up. - * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free - * of irqs. Use dev_id. - * Christoph Hellwig : adapted to module_init/module_exit - * Aki Laukkanen : added power management support - * Arnaldo C. de Melo : added missing restore_flags in ad1848_resume - * Miguel Freitas : added ISA PnP support - * Alan Cox : Added CS4236->4239 identification - * Daniel T. Cobra : Alernate config/mixer for later chips - * Alan Cox : Merged chip idents and config code - * - * TODO - * APM save restore assist code on IBM thinkpad - * - * Status: - * Tested. Believed fully functional. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/stddef.h> -#include <linux/slab.h> -#include <linux/isapnp.h> -#include <linux/pnp.h> -#include <linux/spinlock.h> - -#include "sound_config.h" - -#include "ad1848.h" -#include "ad1848_mixer.h" - -typedef struct -{ - spinlock_t lock; - int base; - int irq; - int dma1, dma2; - int dual_dma; /* 1, when two DMA channels allocated */ - int subtype; - unsigned char MCE_bit; - unsigned char saved_regs[64]; /* Includes extended register space */ - int debug_flag; - - int audio_flags; - int record_dev, playback_dev; - - int xfer_count; - int audio_mode; - int open_mode; - int intr_active; - char *chip_name, *name; - int model; -#define MD_1848 1 -#define MD_4231 2 -#define MD_4231A 3 -#define MD_1845 4 -#define MD_4232 5 -#define MD_C930 6 -#define MD_IWAVE 7 -#define MD_4235 8 /* Crystal Audio CS4235 */ -#define MD_1845_SSCAPE 9 /* Ensoniq Soundscape PNP*/ -#define MD_4236 10 /* 4236 and higher */ -#define MD_42xB 11 /* CS 42xB */ -#define MD_4239 12 /* CS4239 */ - - /* Mixer parameters */ - int recmask; - int supported_devices, orig_devices; - int supported_rec_devices, orig_rec_devices; - int *levels; - short mixer_reroute[32]; - int dev_no; - volatile unsigned long timer_ticks; - int timer_running; - int irq_ok; - mixer_ents *mix_devices; - int mixer_output_port; -} ad1848_info; - -typedef struct ad1848_port_info -{ - int open_mode; - int speed; - unsigned char speed_bits; - int channels; - int audio_format; - unsigned char format_bits; -} -ad1848_port_info; - -static struct address_info cfg; -static int nr_ad1848_devs; - -static bool deskpro_xl; -static bool deskpro_m; -static bool soundpro; - -#ifndef EXCLUDE_TIMERS -static int timer_installed = -1; -#endif - -static int loaded; - -static int ad_format_mask[13 /*devc->model */ ] = -{ - 0, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE /* CS4235 */, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM -}; - -static ad1848_info adev_info[MAX_AUDIO_DEV]; - -#define io_Index_Addr(d) ((d)->base) -#define io_Indexed_Data(d) ((d)->base+1) -#define io_Status(d) ((d)->base+2) -#define io_Polled_IO(d) ((d)->base+3) - -static struct { - unsigned char flags; -#define CAP_F_TIMER 0x01 -} capabilities [10 /*devc->model */ ] = { - {0} - ,{0} /* MD_1848 */ - ,{CAP_F_TIMER} /* MD_4231 */ - ,{CAP_F_TIMER} /* MD_4231A */ - ,{CAP_F_TIMER} /* MD_1845 */ - ,{CAP_F_TIMER} /* MD_4232 */ - ,{0} /* MD_C930 */ - ,{CAP_F_TIMER} /* MD_IWAVE */ - ,{0} /* MD_4235 */ - ,{CAP_F_TIMER} /* MD_1845_SSCAPE */ -}; - -#ifdef CONFIG_PNP -static int isapnp = 1; -static int isapnpjump; -static bool reverse; - -static int audio_activated; -#else -static int isapnp; -#endif - - - -static int ad1848_open(int dev, int mode); -static void ad1848_close(int dev); -static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag); -static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag); -static int ad1848_prepare_for_output(int dev, int bsize, int bcount); -static int ad1848_prepare_for_input(int dev, int bsize, int bcount); -static void ad1848_halt(int dev); -static void ad1848_halt_input(int dev); -static void ad1848_halt_output(int dev); -static void ad1848_trigger(int dev, int bits); -static irqreturn_t adintr(int irq, void *dev_id); - -#ifndef EXCLUDE_TIMERS -static int ad1848_tmr_install(int dev); -static void ad1848_tmr_reprogram(int dev); -#endif - -static int ad_read(ad1848_info * devc, int reg) -{ - int x; - int timeout = 900000; - - while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ - timeout--; - - if(reg < 32) - { - outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - x = inb(io_Indexed_Data(devc)); - } - else - { - int xreg, xra; - - xreg = (reg & 0xff) - 32; - xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2); - outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); - x = inb(io_Indexed_Data(devc)); - } - - return x; -} - -static void ad_write(ad1848_info * devc, int reg, int data) -{ - int timeout = 900000; - - while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */ - timeout--; - - if(reg < 32) - { - outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc)); - } - else - { - int xreg, xra; - - xreg = (reg & 0xff) - 32; - xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2); - outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); - outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); - outb((unsigned char) (data & 0xff), io_Indexed_Data(devc)); - } -} - -static void wait_for_calibration(ad1848_info * devc) -{ - int timeout; - - /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on and then off. - */ - - timeout = 100000; - while (timeout > 0 && inb(devc->base) == 0x80) - timeout--; - if (inb(devc->base) & 0x80) - printk(KERN_WARNING "ad1848: Auto calibration timed out(1).\n"); - - timeout = 100; - while (timeout > 0 && !(ad_read(devc, 11) & 0x20)) - timeout--; - if (!(ad_read(devc, 11) & 0x20)) - return; - - timeout = 80000; - while (timeout > 0 && (ad_read(devc, 11) & 0x20)) - timeout--; - if (ad_read(devc, 11) & 0x20) - if ((devc->model != MD_1845) && (devc->model != MD_1845_SSCAPE)) - printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n"); -} - -static void ad_mute(ad1848_info * devc) -{ - int i; - unsigned char prev; - - /* - * Save old register settings and mute output channels - */ - - for (i = 6; i < 8; i++) - { - prev = devc->saved_regs[i] = ad_read(devc, i); - } - -} - -static void ad_unmute(ad1848_info * devc) -{ -} - -static void ad_enter_MCE(ad1848_info * devc) -{ - int timeout = 1000; - unsigned short prev; - - while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ - timeout--; - - devc->MCE_bit = 0x40; - prev = inb(io_Index_Addr(devc)); - if (prev & 0x40) - { - return; - } - outb((devc->MCE_bit), io_Index_Addr(devc)); -} - -static void ad_leave_MCE(ad1848_info * devc) -{ - unsigned char prev, acal; - int timeout = 1000; - - while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ - timeout--; - - acal = ad_read(devc, 9); - - devc->MCE_bit = 0x00; - prev = inb(io_Index_Addr(devc)); - outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ - - if ((prev & 0x40) == 0) /* Not in MCE mode */ - { - return; - } - outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ - if (acal & 0x08) /* Auto calibration is enabled */ - wait_for_calibration(devc); -} - -static int ad1848_set_recmask(ad1848_info * devc, int mask) -{ - unsigned char recdev; - int i, n; - unsigned long flags; - - mask &= devc->supported_rec_devices; - - /* Rename the mixer bits if necessary */ - for (i = 0; i < 32; i++) - { - if (devc->mixer_reroute[i] != i) - { - if (mask & (1 << i)) - { - mask &= ~(1 << i); - mask |= (1 << devc->mixer_reroute[i]); - } - } - } - - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - spin_lock_irqsave(&devc->lock,flags); - if (!soundpro) { - if (n == 0) - mask = SOUND_MASK_MIC; - else if (n != 1) { /* Too many devices selected */ - mask &= ~devc->recmask; /* Filter out active settings */ - - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - if (n != 1) - mask = SOUND_MASK_MIC; - } - switch (mask) { - case SOUND_MASK_MIC: - recdev = 2; - break; - - case SOUND_MASK_LINE: - case SOUND_MASK_LINE3: - recdev = 0; - break; - - case SOUND_MASK_CD: - case SOUND_MASK_LINE1: - recdev = 1; - break; - - case SOUND_MASK_IMIX: - recdev = 3; - break; - - default: - mask = SOUND_MASK_MIC; - recdev = 2; - } - - recdev <<= 6; - ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); - ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); - } else { /* soundpro */ - unsigned char val; - int set_rec_bit; - int j; - - for (i = 0; i < 32; i++) { /* For each bit */ - if ((devc->supported_rec_devices & (1 << i)) == 0) - continue; /* Device not supported */ - - for (j = LEFT_CHN; j <= RIGHT_CHN; j++) { - if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */ - continue; - - /* - * This is tricky: - * set_rec_bit becomes 1 if the corresponding bit in mask is set - * then it gets flipped if the polarity is inverse - */ - set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol; - - val = ad_read(devc, devc->mix_devices[i][j].recreg); - val &= ~(1 << devc->mix_devices[i][j].recpos); - val |= (set_rec_bit << devc->mix_devices[i][j].recpos); - ad_write(devc, devc->mix_devices[i][j].recreg, val); - } - } - } - spin_unlock_irqrestore(&devc->lock,flags); - - /* Rename the mixer bits back if necessary */ - for (i = 0; i < 32; i++) - { - if (devc->mixer_reroute[i] != i) - { - if (mask & (1 << devc->mixer_reroute[i])) - { - mask &= ~(1 << devc->mixer_reroute[i]); - mask |= (1 << i); - } - } - } - devc->recmask = mask; - return mask; -} - -static void oss_change_bits(ad1848_info *devc, unsigned char *regval, - unsigned char *muteval, int dev, int chn, int newval) -{ - unsigned char mask; - int shift; - int mute; - int mutemask; - int set_mute_bit; - - set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol; - - if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ - newval = 100 - newval; - - mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; - shift = devc->mix_devices[dev][chn].bitpos; - - if (devc->mix_devices[dev][chn].mutepos == 8) - { /* if there is no mute bit */ - mute = 0; /* No mute bit; do nothing special */ - mutemask = ~0; /* No mute bit; do nothing special */ - } - else - { - mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); - mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); - } - - newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= ~(mask << shift); /* Clear bits */ - *regval |= (newval & mask) << shift; /* Set new value */ - - *muteval &= mutemask; - *muteval |= mute; -} - -static int ad1848_mixer_get(ad1848_info * devc, int dev) -{ - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; - - dev = devc->mixer_reroute[dev]; - - return devc->levels[dev]; -} - -static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel) -{ - int regoffs, muteregoffs; - unsigned char val, muteval; - unsigned long flags; - - regoffs = devc->mix_devices[dev][channel].regno; - muteregoffs = devc->mix_devices[dev][channel].mutereg; - val = ad_read(devc, regoffs); - - if (muteregoffs != regoffs) { - muteval = ad_read(devc, muteregoffs); - oss_change_bits(devc, &val, &muteval, dev, channel, value); - } - else - oss_change_bits(devc, &val, &val, dev, channel, value); - - spin_lock_irqsave(&devc->lock,flags); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; - if (muteregoffs != regoffs) { - ad_write(devc, muteregoffs, muteval); - devc->saved_regs[muteregoffs] = muteval; - } - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retvol; - - if (dev > 31) - return -EINVAL; - - if (!(devc->supported_devices & (1 << dev))) - return -EINVAL; - - dev = devc->mixer_reroute[dev]; - - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ - right = left; - - retvol = left | (right << 8); - - /* Scale volumes */ - left = mix_cvt[left]; - right = mix_cvt[right]; - - devc->levels[dev] = retvol; - - /* - * Set the left channel - */ - ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN); - - /* - * Set the right channel - */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - goto out; - ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); - - out: - return retvol; -} - -static void ad1848_mixer_reset(ad1848_info * devc) -{ - int i; - char name[32]; - unsigned long flags; - - devc->mix_devices = &(ad1848_mix_devices[0]); - - sprintf(name, "%s_%d", devc->chip_name, nr_ad1848_devs); - - for (i = 0; i < 32; i++) - devc->mixer_reroute[i] = i; - - devc->supported_rec_devices = MODE1_REC_DEVICES; - - switch (devc->model) - { - case MD_4231: - case MD_4231A: - case MD_1845: - case MD_1845_SSCAPE: - devc->supported_devices = MODE2_MIXER_DEVICES; - break; - - case MD_C930: - devc->supported_devices = C930_MIXER_DEVICES; - devc->mix_devices = &(c930_mix_devices[0]); - break; - - case MD_IWAVE: - devc->supported_devices = MODE3_MIXER_DEVICES; - devc->mix_devices = &(iwave_mix_devices[0]); - break; - - case MD_42xB: - case MD_4239: - devc->mix_devices = &(cs42xb_mix_devices[0]); - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - case MD_4232: - case MD_4235: - case MD_4236: - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - - case MD_1848: - if (soundpro) { - devc->supported_devices = SPRO_MIXER_DEVICES; - devc->supported_rec_devices = SPRO_REC_DEVICES; - devc->mix_devices = &(spro_mix_devices[0]); - break; - } - - default: - devc->supported_devices = MODE1_MIXER_DEVICES; - } - - devc->orig_devices = devc->supported_devices; - devc->orig_rec_devices = devc->supported_rec_devices; - - devc->levels = load_mixer_volumes(name, default_mixer_levels, 1); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - { - if (devc->supported_devices & (1 << i)) - ad1848_mixer_set(devc, i, devc->levels[i]); - } - - ad1848_set_recmask(devc, SOUND_MASK_MIC); - - devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; - - spin_lock_irqsave(&devc->lock,flags); - if (!soundpro) { - if (devc->mixer_output_port & AUDIO_SPEAKER) - ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ - } else { - /* - * From the "wouldn't it be nice if the mixer API had (better) - * support for custom stuff" category - */ - /* Enable surround mode and SB16 mixer */ - ad_write(devc, 16, 0x60); - } - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int ad1848_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - ad1848_info *devc = mixer_devs[dev]->devc; - int val; - - if (cmd == SOUND_MIXER_PRIVATE1) - { - if (get_user(val, (int __user *)arg)) - return -EFAULT; - - if (val != 0xffff) - { - unsigned long flags; - val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); - devc->mixer_output_port = val; - val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ - devc->mixer_output_port = val; - spin_lock_irqsave(&devc->lock,flags); - if (val & AUDIO_SPEAKER) - ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ - spin_unlock_irqrestore(&devc->lock,flags); - } - val = devc->mixer_output_port; - return put_user(val, (int __user *)arg); - } - if (cmd == SOUND_MIXER_PRIVATE2) - { - if (get_user(val, (int __user *)arg)) - return -EFAULT; - return(ad1848_control(AD1848_MIXER_REROUTE, val)); - } - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - { - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = ad1848_set_recmask(devc, val); - break; - - default: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = ad1848_mixer_set(devc, cmd & 0xff, val); - break; - } - return put_user(val, (int __user *)arg); - } - else - { - switch (cmd & 0xff) - { - /* - * Return parameters - */ - - case SOUND_MIXER_RECSRC: - val = devc->recmask; - break; - - case SOUND_MIXER_DEVMASK: - val = devc->supported_devices; - break; - - case SOUND_MIXER_STEREODEVS: - val = devc->supported_devices; - if (devc->model != MD_C930) - val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - break; - - case SOUND_MIXER_RECMASK: - val = devc->supported_rec_devices; - break; - - case SOUND_MIXER_CAPS: - val=SOUND_CAP_EXCL_INPUT; - break; - - default: - val = ad1848_mixer_get(devc, cmd & 0xff); - break; - } - return put_user(val, (int __user *)arg); - } - } - else - return -EINVAL; -} - -static int ad1848_set_speed(int dev, int arg) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - /* - * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other - * three bits select the divisor (indirectly): - * - * The available speeds are in the following table. Keep the speeds in - * the increasing order. - */ - typedef struct - { - int speed; - unsigned char bits; - } - speed_struct; - - static speed_struct speed_table[] = - { - {5510, (0 << 1) | 1}, - {5510, (0 << 1) | 1}, - {6620, (7 << 1) | 1}, - {8000, (0 << 1) | 0}, - {9600, (7 << 1) | 0}, - {11025, (1 << 1) | 1}, - {16000, (1 << 1) | 0}, - {18900, (2 << 1) | 1}, - {22050, (3 << 1) | 1}, - {27420, (2 << 1) | 0}, - {32000, (3 << 1) | 0}, - {33075, (6 << 1) | 1}, - {37800, (4 << 1) | 1}, - {44100, (5 << 1) | 1}, - {48000, (6 << 1) | 0} - }; - - int i, n, selected = -1; - - n = sizeof(speed_table) / sizeof(speed_struct); - - if (arg <= 0) - return portc->speed; - - if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) /* AD1845 has different timer than others */ - { - if (arg < 4000) - arg = 4000; - if (arg > 50000) - arg = 50000; - - portc->speed = arg; - portc->speed_bits = speed_table[3].bits; - return portc->speed; - } - if (arg < speed_table[0].speed) - selected = 0; - if (arg > speed_table[n - 1].speed) - selected = n - 1; - - for (i = 1 /*really */ ; selected == -1 && i < n; i++) - { - if (speed_table[i].speed == arg) - selected = i; - else if (speed_table[i].speed > arg) - { - int diff1, diff2; - - diff1 = arg - speed_table[i - 1].speed; - diff2 = speed_table[i].speed - arg; - - if (diff1 < diff2) - selected = i - 1; - else - selected = i; - } - } - if (selected == -1) - { - printk(KERN_WARNING "ad1848: Can't find speed???\n"); - selected = 3; - } - portc->speed = speed_table[selected].speed; - portc->speed_bits = speed_table[selected].bits; - return portc->speed; -} - -static short ad1848_set_channels(int dev, short arg) -{ - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - if (arg != 1 && arg != 2) - return portc->channels; - - portc->channels = arg; - return arg; -} - -static unsigned int ad1848_set_bits(int dev, unsigned int arg) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - static struct format_tbl - { - int format; - unsigned char bits; - } - format2bits[] = - { - { - 0, 0 - } - , - { - AFMT_MU_LAW, 1 - } - , - { - AFMT_A_LAW, 3 - } - , - { - AFMT_IMA_ADPCM, 5 - } - , - { - AFMT_U8, 0 - } - , - { - AFMT_S16_LE, 2 - } - , - { - AFMT_S16_BE, 6 - } - , - { - AFMT_S8, 0 - } - , - { - AFMT_U16_LE, 0 - } - , - { - AFMT_U16_BE, 0 - } - }; - int i, n = sizeof(format2bits) / sizeof(struct format_tbl); - - if (arg == 0) - return portc->audio_format; - - if (!(arg & ad_format_mask[devc->model])) - arg = AFMT_U8; - - portc->audio_format = arg; - - for (i = 0; i < n; i++) - if (format2bits[i].format == arg) - { - if ((portc->format_bits = format2bits[i].bits) == 0) - return portc->audio_format = AFMT_U8; /* Was not supported */ - - return arg; - } - /* Still hanging here. Something must be terribly wrong */ - portc->format_bits = 0; - return portc->audio_format = AFMT_U8; -} - -static struct audio_driver ad1848_audio_driver = -{ - .owner = THIS_MODULE, - .open = ad1848_open, - .close = ad1848_close, - .output_block = ad1848_output_block, - .start_input = ad1848_start_input, - .prepare_for_input = ad1848_prepare_for_input, - .prepare_for_output = ad1848_prepare_for_output, - .halt_io = ad1848_halt, - .halt_input = ad1848_halt_input, - .halt_output = ad1848_halt_output, - .trigger = ad1848_trigger, - .set_speed = ad1848_set_speed, - .set_bits = ad1848_set_bits, - .set_channels = ad1848_set_channels -}; - -static struct mixer_operations ad1848_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "SOUNDPORT", - .name = "AD1848/CS4248/CS4231", - .ioctl = ad1848_mixer_ioctl -}; - -static int ad1848_open(int dev, int mode) -{ - ad1848_info *devc; - ad1848_port_info *portc; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (ad1848_info *) audio_devs[dev]->devc; - portc = (ad1848_port_info *) audio_devs[dev]->portc; - - /* here we don't have to protect against intr */ - spin_lock(&devc->lock); - if (portc->open_mode || (devc->open_mode & mode)) - { - spin_unlock(&devc->lock); - return -EBUSY; - } - devc->dual_dma = 0; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - devc->dual_dma = 1; - } - devc->intr_active = 0; - devc->audio_mode = 0; - devc->open_mode |= mode; - portc->open_mode = mode; - spin_unlock(&devc->lock); - ad1848_trigger(dev, 0); - - if (mode & OPEN_READ) - devc->record_dev = dev; - if (mode & OPEN_WRITE) - devc->playback_dev = dev; -/* - * Mute output until the playback really starts. This decreases clicking (hope so). - */ - spin_lock_irqsave(&devc->lock,flags); - ad_mute(devc); - spin_unlock_irqrestore(&devc->lock,flags); - - return 0; -} - -static void ad1848_close(int dev) -{ - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - devc->intr_active = 0; - ad1848_halt(dev); - - spin_lock_irqsave(&devc->lock,flags); - - devc->audio_mode = 0; - devc->open_mode &= ~portc->open_mode; - portc->open_mode = 0; - - ad_unmute(devc); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag) -{ - unsigned long flags, cnt; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - cnt = count; - - if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } - else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } - if (portc->channels > 1) - cnt >>= 1; - cnt--; - - if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - return; /* - * Auto DMA mode on. No need to react - */ - } - spin_lock_irqsave(&devc->lock,flags); - - ad_write(devc, 15, (unsigned char) (cnt & 0xff)); - ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - - devc->xfer_count = cnt; - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag) -{ - unsigned long flags, cnt; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - cnt = count; - if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } - else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } - if (portc->channels > 1) - cnt >>= 1; - cnt--; - - if ((devc->audio_mode & PCM_ENABLE_INPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - return; /* - * Auto DMA mode on. No need to react - */ - } - spin_lock_irqsave(&devc->lock,flags); - - if (devc->model == MD_1848) - { - ad_write(devc, 15, (unsigned char) (cnt & 0xff)); - ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - } - else - { - ad_write(devc, 31, (unsigned char) (cnt & 0xff)); - ad_write(devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); - } - - ad_unmute(devc); - - devc->xfer_count = cnt; - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int ad1848_prepare_for_output(int dev, int bsize, int bcount) -{ - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - ad_mute(devc); - - spin_lock_irqsave(&devc->lock,flags); - fs = portc->speed_bits | (portc->format_bits << 5); - - if (portc->channels > 1) - fs |= 0x10; - - ad_enter_MCE(devc); /* Enables changes to the format select reg */ - - if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ - - ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ - } - old_fs = ad_read(devc, 8); - - if (devc->model == MD_4232 || devc->model >= MD_4236) - { - tmp = ad_read(devc, 16); - ad_write(devc, 16, tmp | 0x30); - } - if (devc->model == MD_IWAVE) - ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ - - ad_write(devc, 8, fs); - - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - - if (devc->model >= MD_4232) - ad_write(devc, 16, tmp & ~0x30); - - ad_leave_MCE(devc); /* - * Starts the calibration process. - */ - spin_unlock_irqrestore(&devc->lock,flags); - devc->xfer_count = 0; - -#ifndef EXCLUDE_TIMERS - if (dev == timer_installed && devc->timer_running) - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram(dev); - } -#endif - ad1848_halt_output(dev); - return 0; -} - -static int ad1848_prepare_for_input(int dev, int bsize, int bcount) -{ - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - if (devc->audio_mode) - return 0; - - spin_lock_irqsave(&devc->lock,flags); - fs = portc->speed_bits | (portc->format_bits << 5); - - if (portc->channels > 1) - fs |= 0x10; - - ad_enter_MCE(devc); /* Enables changes to the format select reg */ - - if ((devc->model == MD_1845) || (devc->model == MD_1845_SSCAPE)) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ - - ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ - } - if (devc->model == MD_4232) - { - tmp = ad_read(devc, 16); - ad_write(devc, 16, tmp | 0x30); - } - if (devc->model == MD_IWAVE) - ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ - - /* - * If mode >= 2 (CS4231), set I28. It's the capture format register. - */ - - if (devc->model != MD_1848) - { - old_fs = ad_read(devc, 28); - ad_write(devc, 28, fs); - - /* - * Write to I28 starts resynchronization. Wait until it completes. - */ - - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - - if (devc->model != MD_1848 && devc->model != MD_1845 && devc->model != MD_1845_SSCAPE) - { - /* - * CS4231 compatible devices don't have separate sampling rate selection - * register for recording an playback. The I8 register is shared so we have to - * set the speed encoding bits of it too. - */ - unsigned char tmp = portc->speed_bits | (ad_read(devc, 8) & 0xf0); - - ad_write(devc, 8, tmp); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - } - } - else - { /* For AD1848 set I8. */ - - old_fs = ad_read(devc, 8); - ad_write(devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - } - - if (devc->model == MD_4232) - ad_write(devc, 16, tmp & ~0x30); - - ad_leave_MCE(devc); /* - * Starts the calibration process. - */ - spin_unlock_irqrestore(&devc->lock,flags); - devc->xfer_count = 0; - -#ifndef EXCLUDE_TIMERS - if (dev == timer_installed && devc->timer_running) - { - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram(dev); - } - } -#endif - ad1848_halt_input(dev); - return 0; -} - -static void ad1848_halt(int dev) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - unsigned char bits = ad_read(devc, 9); - - if (bits & 0x01 && (portc->open_mode & OPEN_WRITE)) - ad1848_halt_output(dev); - - if (bits & 0x02 && (portc->open_mode & OPEN_READ)) - ad1848_halt_input(dev); - devc->audio_mode = 0; -} - -static void ad1848_halt_input(int dev) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; - - if (!(ad_read(devc, 9) & 0x02)) - return; /* Capture not enabled */ - - spin_lock_irqsave(&devc->lock,flags); - - ad_mute(devc); - - { - int tmout; - - if(!isa_dma_bridge_buggy) - disable_dma(audio_devs[dev]->dmap_in->dma); - - for (tmout = 0; tmout < 100000; tmout++) - if (ad_read(devc, 11) & 0x10) - break; - ad_write(devc, 9, ad_read(devc, 9) & ~0x02); /* Stop capture */ - - if(!isa_dma_bridge_buggy) - enable_dma(audio_devs[dev]->dmap_in->dma); - devc->audio_mode &= ~PCM_ENABLE_INPUT; - } - - outb(0, io_Status(devc)); /* Clear interrupt status */ - outb(0, io_Status(devc)); /* Clear interrupt status */ - - devc->audio_mode &= ~PCM_ENABLE_INPUT; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_halt_output(int dev) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; - - if (!(ad_read(devc, 9) & 0x01)) - return; /* Playback not enabled */ - - spin_lock_irqsave(&devc->lock,flags); - - ad_mute(devc); - { - int tmout; - - if(!isa_dma_bridge_buggy) - disable_dma(audio_devs[dev]->dmap_out->dma); - - for (tmout = 0; tmout < 100000; tmout++) - if (ad_read(devc, 11) & 0x10) - break; - ad_write(devc, 9, ad_read(devc, 9) & ~0x01); /* Stop playback */ - - if(!isa_dma_bridge_buggy) - enable_dma(audio_devs[dev]->dmap_out->dma); - - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - } - - outb((0), io_Status(devc)); /* Clear interrupt status */ - outb((0), io_Status(devc)); /* Clear interrupt status */ - - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_trigger(int dev, int state) -{ - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - unsigned long flags; - unsigned char tmp, old; - - spin_lock_irqsave(&devc->lock,flags); - state &= devc->audio_mode; - - tmp = old = ad_read(devc, 9); - - if (portc->open_mode & OPEN_READ) - { - if (state & PCM_ENABLE_INPUT) - tmp |= 0x02; - else - tmp &= ~0x02; - } - if (portc->open_mode & OPEN_WRITE) - { - if (state & PCM_ENABLE_OUTPUT) - tmp |= 0x01; - else - tmp &= ~0x01; - } - /* ad_mute(devc); */ - if (tmp != old) - { - ad_write(devc, 9, tmp); - ad_unmute(devc); - } - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_init_hw(ad1848_info * devc) -{ - int i; - int *init_values; - - /* - * Initial values for the indirect registers of CS4248/AD1848. - */ - static int init_values_a[] = - { - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, - - /* Positions 16 to 31 just for CS4231/2 and ad1845 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - static int init_values_b[] = - { - /* - Values for the newer chips - Some of the register initialization values were changed. In - order to get rid of the click that preceded PCM playback, - calibration was disabled on the 10th byte. On that same byte, - dual DMA was enabled; on the 11th byte, ADC dithering was - enabled, since that is theoretically desirable; on the 13th - byte, Mode 3 was selected, to enable access to extended - registers. - */ - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x06, 0x00, 0xe0, 0x01, 0x00, 0x00, - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - /* - * Select initialisation data - */ - - init_values = init_values_a; - if(devc->model >= MD_4236) - init_values = init_values_b; - - for (i = 0; i < 16; i++) - ad_write(devc, i, init_values[i]); - - - ad_mute(devc); /* Initialize some variables */ - ad_unmute(devc); /* Leave it unmuted now */ - - if (devc->model > MD_1848) - { - if (devc->model == MD_1845_SSCAPE) - ad_write(devc, 12, ad_read(devc, 12) | 0x50); - else - ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - - if (devc->model == MD_IWAVE) - ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - - if (devc->model != MD_1845_SSCAPE) - for (i = 16; i < 32; i++) - ad_write(devc, i, init_values[i]); - - if (devc->model == MD_IWAVE) - ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ - } - if (devc->model > MD_1848) - { - if (devc->audio_flags & DMA_DUPLEX) - ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */ - else - ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ - - if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) - ad_write(devc, 27, ad_read(devc, 27) | 0x08); /* Alternate freq select enabled */ - - if (devc->model == MD_IWAVE) - { /* Some magic Interwave specific initialization */ - ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ - ad_write(devc, 17, 0xc2); /* Alternate feature enable */ - } - } - else - { - devc->audio_flags &= ~DMA_DUPLEX; - ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ - if (soundpro) - ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - } - - outb((0), io_Status(devc)); /* Clear pending interrupts */ - - /* - * Toggle the MCE bit. It completes the initialization phase. - */ - - ad_enter_MCE(devc); /* In case the bit was off */ - ad_leave_MCE(devc); - - ad1848_mixer_reset(devc); -} - -int ad1848_detect(struct resource *ports, int *ad_flags, int *osp) -{ - unsigned char tmp; - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - unsigned char tmp1 = 0xff, tmp2 = 0xff; - int optiC930 = 0; /* OPTi 82C930 flag */ - int interwave = 0; - int ad1847_flag = 0; - int cs4248_flag = 0; - int sscape_flag = 0; - int io_base = ports->start; - - int i; - - DDB(printk("ad1848_detect(%x)\n", io_base)); - - if (ad_flags) - { - if (*ad_flags == 0x12345678) - { - interwave = 1; - *ad_flags = 0; - } - - if (*ad_flags == 0x87654321) - { - sscape_flag = 1; - *ad_flags = 0; - } - - if (*ad_flags == 0x12345677) - { - cs4248_flag = 1; - *ad_flags = 0; - } - } - if (nr_ad1848_devs >= MAX_AUDIO_DEV) - { - printk(KERN_ERR "ad1848 - Too many audio devices\n"); - return 0; - } - spin_lock_init(&devc->lock); - devc->base = io_base; - devc->irq_ok = 0; - devc->timer_running = 0; - devc->MCE_bit = 0x40; - devc->irq = 0; - devc->open_mode = 0; - devc->chip_name = devc->name = "AD1848"; - devc->model = MD_1848; /* AD1848 or CS4248 */ - devc->levels = NULL; - devc->debug_flag = 0; - - /* - * Check that the I/O address is in use. - * - * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power on initialization. Just assume - * this has happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. - */ - - if (inb(devc->base) == 0xff) - { - DDB(printk("ad1848_detect: The base I/O address appears to be dead\n")); - } - - /* - * Wait for the device to stop initialization - */ - - DDB(printk("ad1848_detect() - step 0\n")); - - for (i = 0; i < 10000000; i++) - { - unsigned char x = inb(devc->base); - - if (x == 0xff || !(x & 0x80)) - break; - } - - DDB(printk("ad1848_detect() - step A\n")); - - if (inb(devc->base) == 0x80) /* Not ready. Let's wait */ - ad_leave_MCE(devc); - - if ((inb(devc->base) & 0x80) != 0x00) /* Not a AD1848 */ - { - DDB(printk("ad1848 detect error - step A (%02x)\n", (int) inb(devc->base))); - return 0; - } - - /* - * Test if it's possible to change contents of the indirect registers. - * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only - * so try to avoid using it. - */ - - DDB(printk("ad1848_detect() - step B\n")); - ad_write(devc, 0, 0xaa); - ad_write(devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ - - if ((tmp1 = ad_read(devc, 0)) != 0xaa || (tmp2 = ad_read(devc, 1)) != 0x45) - { - if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ - ad1847_flag = 1; - else - { - DDB(printk("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); - return 0; - } - } - DDB(printk("ad1848_detect() - step C\n")); - ad_write(devc, 0, 0x45); - ad_write(devc, 1, 0xaa); - - if ((tmp1 = ad_read(devc, 0)) != 0x45 || (tmp2 = ad_read(devc, 1)) != 0xaa) - { - if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ - ad1847_flag = 1; - else - { - DDB(printk("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); - return 0; - } - } - - /* - * The indirect register I12 has some read only bits. Let's - * try to change them. - */ - - DDB(printk("ad1848_detect() - step D\n")); - tmp = ad_read(devc, 12); - ad_write(devc, 12, (~tmp) & 0x0f); - - if ((tmp & 0x0f) != ((tmp1 = ad_read(devc, 12)) & 0x0f)) - { - DDB(printk("ad1848 detect error - step D (%x)\n", tmp1)); - return 0; - } - - /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB and 0x0A=RevC. - */ - - /* - * The original AD1848/CS4248 has just 15 indirect registers. This means - * that I0 and I16 should return the same value (etc.). - * However this doesn't work with CS4248. Actually it seems to be impossible - * to detect if the chip is a CS4231 or CS4248. - * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with CS4231. - */ - - /* - * OPTi 82C930 has mode2 control bit in another place. This test will fail - * with it. Accept this situation as a possible indication of this chip. - */ - - DDB(printk("ad1848_detect() - step F\n")); - ad_write(devc, 12, 0); /* Mode2=disabled */ - - for (i = 0; i < 16; i++) - { - if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) - { - DDB(printk("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); - if (!ad1847_flag) - optiC930 = 1; - break; - } - } - - /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). - * The bit 0x80 is always 1 in CS4248 and CS4231. - */ - - DDB(printk("ad1848_detect() - step G\n")); - - if (ad_flags && *ad_flags == 400) - *ad_flags = 0; - else - ad_write(devc, 12, 0x40); /* Set mode2, clear 0x80 */ - - - if (ad_flags) - *ad_flags = 0; - - tmp1 = ad_read(devc, 12); - if (tmp1 & 0x80) - { - if (ad_flags) - *ad_flags |= AD_F_CS4248; - - devc->chip_name = "CS4248"; /* Our best knowledge just now */ - } - if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) - { - /* - * CS4231 detected - is it? - * - * Verify that setting I0 doesn't change I16. - */ - - DDB(printk("ad1848_detect() - step H\n")); - ad_write(devc, 16, 0); /* Set I16 to known value */ - - ad_write(devc, 0, 0x45); - if ((tmp1 = ad_read(devc, 16)) != 0x45) /* No change -> CS4231? */ - { - ad_write(devc, 0, 0xaa); - if ((tmp1 = ad_read(devc, 16)) == 0xaa) /* Rotten bits? */ - { - DDB(printk("ad1848 detect error - step H(%x)\n", tmp1)); - return 0; - } - - /* - * Verify that some bits of I25 are read only. - */ - - DDB(printk("ad1848_detect() - step I\n")); - tmp1 = ad_read(devc, 25); /* Original bits */ - ad_write(devc, 25, ~tmp1); /* Invert all bits */ - if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) - { - int id; - - /* - * It's at least CS4231 - */ - - devc->chip_name = "CS4231"; - devc->model = MD_4231; - - /* - * It could be an AD1845 or CS4231A as well. - * CS4231 and AD1845 report the same revision info in I25 - * while the CS4231A reports different. - */ - - id = ad_read(devc, 25); - if ((id & 0xe7) == 0x80) /* Device busy??? */ - id = ad_read(devc, 25); - if ((id & 0xe7) == 0x80) /* Device still busy??? */ - id = ad_read(devc, 25); - DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25))); - - if ((id & 0xe7) == 0x80) { - /* - * It must be a CS4231 or AD1845. The register I23 of - * CS4231 is undefined and it appears to be read only. - * AD1845 uses I23 for setting sample rate. Assume - * the chip is AD1845 if I23 is changeable. - */ - - unsigned char tmp = ad_read(devc, 23); - ad_write(devc, 23, ~tmp); - - if (interwave) - { - devc->model = MD_IWAVE; - devc->chip_name = "IWave"; - } - else if (ad_read(devc, 23) != tmp) /* AD1845 ? */ - { - devc->chip_name = "AD1845"; - devc->model = MD_1845; - } - else if (cs4248_flag) - { - if (ad_flags) - *ad_flags |= AD_F_CS4248; - devc->chip_name = "CS4248"; - devc->model = MD_1848; - ad_write(devc, 12, ad_read(devc, 12) & ~0x40); /* Mode2 off */ - } - ad_write(devc, 23, tmp); /* Restore */ - } - else - { - switch (id & 0x1f) { - case 3: /* CS4236/CS4235/CS42xB/CS4239 */ - { - int xid; - ad_write(devc, 12, ad_read(devc, 12) | 0x60); /* switch to mode 3 */ - ad_write(devc, 23, 0x9c); /* select extended register 25 */ - xid = inb(io_Indexed_Data(devc)); - ad_write(devc, 12, ad_read(devc, 12) & ~0x60); /* back to mode 0 */ - switch (xid & 0x1f) - { - case 0x00: - devc->chip_name = "CS4237B(B)"; - devc->model = MD_42xB; - break; - case 0x08: - /* Seems to be a 4238 ?? */ - devc->chip_name = "CS4238"; - devc->model = MD_42xB; - break; - case 0x09: - devc->chip_name = "CS4238B"; - devc->model = MD_42xB; - break; - case 0x0b: - devc->chip_name = "CS4236B"; - devc->model = MD_4236; - break; - case 0x10: - devc->chip_name = "CS4237B"; - devc->model = MD_42xB; - break; - case 0x1d: - devc->chip_name = "CS4235"; - devc->model = MD_4235; - break; - case 0x1e: - devc->chip_name = "CS4239"; - devc->model = MD_4239; - break; - default: - printk("Chip ident is %X.\n", xid&0x1F); - devc->chip_name = "CS42xx"; - devc->model = MD_4232; - break; - } - } - break; - - case 2: /* CS4232/CS4232A */ - devc->chip_name = "CS4232"; - devc->model = MD_4232; - break; - - case 0: - if ((id & 0xe0) == 0xa0) - { - devc->chip_name = "CS4231A"; - devc->model = MD_4231A; - } - else - { - devc->chip_name = "CS4321"; - devc->model = MD_4231; - } - break; - - default: /* maybe */ - DDB(printk("ad1848: I25 = %02x/%02x\n", ad_read(devc, 25), ad_read(devc, 25) & 0xe7)); - if (optiC930) - { - devc->chip_name = "82C930"; - devc->model = MD_C930; - } - else - { - devc->chip_name = "CS4231"; - devc->model = MD_4231; - } - } - } - } - ad_write(devc, 25, tmp1); /* Restore bits */ - - DDB(printk("ad1848_detect() - step K\n")); - } - } else if (tmp1 == 0x0a) { - /* - * Is it perhaps a SoundPro CMI8330? - * If so, then we should be able to change indirect registers - * greater than I15 after activating MODE2, even though reading - * back I12 does not show it. - */ - - /* - * Let's try comparing register values - */ - for (i = 0; i < 16; i++) { - if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) { - DDB(printk("ad1848 detect step H(%d/%x/%x) - SoundPro chip?\n", i, tmp1, tmp2)); - soundpro = 1; - devc->chip_name = "SoundPro CMI 8330"; - break; - } - } - } - - DDB(printk("ad1848_detect() - step L\n")); - if (ad_flags) - { - if (devc->model != MD_1848) - *ad_flags |= AD_F_CS4231; - } - DDB(printk("ad1848_detect() - Detected OK\n")); - - if (devc->model == MD_1848 && ad1847_flag) - devc->chip_name = "AD1847"; - - - if (sscape_flag == 1) - devc->model = MD_1845_SSCAPE; - - return 1; -} - -int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback, - int dma_capture, int share_dma, int *osp, struct module *owner) -{ - /* - * 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). - */ - - int my_dev; - char dev_name[100]; - int e; - - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - - ad1848_port_info *portc = NULL; - - devc->irq = (irq > 0) ? irq : 0; - devc->open_mode = 0; - devc->timer_ticks = 0; - devc->dma1 = dma_playback; - devc->dma2 = dma_capture; - devc->subtype = cfg.card_subtype; - devc->audio_flags = DMA_AUTOMODE; - devc->playback_dev = devc->record_dev = 0; - if (name != NULL) - devc->name = name; - - if (name != NULL && name[0] != 0) - sprintf(dev_name, - "%s (%s)", name, devc->chip_name); - else - sprintf(dev_name, - "Generic audio codec (%s)", devc->chip_name); - - rename_region(ports, devc->name); - - conf_printf2(dev_name, devc->base, devc->irq, dma_playback, dma_capture); - - if (devc->model == MD_1848 || devc->model == MD_C930) - devc->audio_flags |= DMA_HARDSTOP; - - if (devc->model > MD_1848) - { - if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) - devc->audio_flags &= ~DMA_DUPLEX; - else - devc->audio_flags |= DMA_DUPLEX; - } - - portc = kmalloc(sizeof(ad1848_port_info), GFP_KERNEL); - if(portc==NULL) { - release_region(devc->base, 4); - return -1; - } - - if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - dev_name, - &ad1848_audio_driver, - sizeof(struct audio_driver), - devc->audio_flags, - ad_format_mask[devc->model], - devc, - dma_playback, - dma_capture)) < 0) - { - release_region(devc->base, 4); - kfree(portc); - return -1; - } - - audio_devs[my_dev]->portc = portc; - audio_devs[my_dev]->mixer_dev = -1; - if (owner) - audio_devs[my_dev]->d->owner = owner; - memset((char *) portc, 0, sizeof(*portc)); - - nr_ad1848_devs++; - - ad1848_init_hw(devc); - - if (irq > 0) - { - devc->dev_no = my_dev; - if (request_irq(devc->irq, adintr, 0, devc->name, - (void *)(long)my_dev) < 0) - { - printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n"); - /* Don't free it either then.. */ - devc->irq = 0; - } - if (capabilities[devc->model].flags & CAP_F_TIMER) - { -#ifndef CONFIG_SMP - int x; - unsigned char tmp = ad_read(devc, 16); -#endif - - devc->timer_ticks = 0; - - ad_write(devc, 21, 0x00); /* Timer MSB */ - ad_write(devc, 20, 0x10); /* Timer LSB */ -#ifndef CONFIG_SMP - ad_write(devc, 16, tmp | 0x40); /* Enable timer */ - for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); - ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ - - if (devc->timer_ticks == 0) - printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", irq); - else - { - DDB(printk("Interrupt test OK\n")); - devc->irq_ok = 1; - } -#else - devc->irq_ok = 1; -#endif - } - else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ - } else if (irq < 0) - devc->dev_no = my_dev; - -#ifndef EXCLUDE_TIMERS - if ((capabilities[devc->model].flags & CAP_F_TIMER) && - devc->irq_ok) - ad1848_tmr_install(my_dev); -#endif - - if (!share_dma) - { - if (sound_alloc_dma(dma_playback, devc->name)) - printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma(dma_capture, devc->name)) - printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_capture); - } - - if ((e = sound_install_mixer(MIXER_DRIVER_VERSION, - dev_name, - &ad1848_mixer_operations, - sizeof(struct mixer_operations), - devc)) >= 0) - { - audio_devs[my_dev]->mixer_dev = e; - if (owner) - mixer_devs[e]->owner = owner; - } - return my_dev; -} - -int ad1848_control(int cmd, int arg) -{ - ad1848_info *devc; - unsigned long flags; - - if (nr_ad1848_devs < 1) - return -ENODEV; - - devc = &adev_info[nr_ad1848_devs - 1]; - - switch (cmd) - { - case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845 && devc->model != MD_1845_SSCAPE) - return -EINVAL; - spin_lock_irqsave(&devc->lock,flags); - ad_enter_MCE(devc); - ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); - ad_leave_MCE(devc); - spin_unlock_irqrestore(&devc->lock,flags); - break; - - case AD1848_MIXER_REROUTE: - { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; - - if (o < 0 || o >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - - if (!(devc->supported_devices & (1 << o)) && - !(devc->supported_rec_devices & (1 << o))) - return -EINVAL; - - if (n == SOUND_MIXER_NONE) - { /* Just hide this control */ - ad1848_mixer_set(devc, o, 0); /* Shut up it */ - devc->supported_devices &= ~(1 << o); - devc->supported_rec_devices &= ~(1 << o); - break; - } - - /* Make the mixer control identified by o to appear as n */ - if (n < 0 || n >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - - devc->mixer_reroute[n] = o; /* Rename the control */ - if (devc->supported_devices & (1 << o)) - devc->supported_devices |= (1 << n); - if (devc->supported_rec_devices & (1 << o)) - devc->supported_rec_devices |= (1 << n); - - devc->supported_devices &= ~(1 << o); - devc->supported_rec_devices &= ~(1 << o); - } - break; - } - return 0; -} - -void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) -{ - int i, mixer, dev = 0; - ad1848_info *devc = NULL; - - for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) - { - if (adev_info[i].base == io_base) - { - devc = &adev_info[i]; - dev = devc->dev_no; - } - } - - if (devc != NULL) - { - kfree(audio_devs[dev]->portc); - release_region(devc->base, 4); - - if (!share_dma) - { - if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */ - free_irq(devc->irq, (void *)(long)devc->dev_no); - - sound_free_dma(dma_playback); - - if (dma_playback != dma_capture) - sound_free_dma(dma_capture); - - } - mixer = audio_devs[devc->dev_no]->mixer_dev; - if(mixer>=0) - sound_unload_mixerdev(mixer); - - nr_ad1848_devs--; - for ( ; i < nr_ad1848_devs ; i++) - adev_info[i] = adev_info[i+1]; - } - else - printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); -} - -static irqreturn_t adintr(int irq, void *dev_id) -{ - unsigned char status; - ad1848_info *devc; - int dev; - int alt_stat = 0xff; - unsigned char c930_stat = 0; - int cnt = 0; - - dev = (long)dev_id; - devc = (ad1848_info *) audio_devs[dev]->devc; - -interrupt_again: /* Jump back here if int status doesn't reset */ - - status = inb(io_Status(devc)); - - if (status == 0x80) - printk(KERN_DEBUG "adintr: Why?\n"); - if (devc->model == MD_1848) - outb((0), io_Status(devc)); /* Clear interrupt status */ - - if (status & 0x01) - { - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - - spin_lock(&devc->lock); - - /* 0xe0e is C930 address port - * 0xe0f is C930 data port - */ - outb(11, 0xe0e); - c930_stat = inb(0xe0f); - outb((~c930_stat), 0xe0f); - - spin_unlock(&devc->lock); - - alt_stat = (c930_stat << 2) & 0x30; - } - else if (devc->model != MD_1848) - { - spin_lock(&devc->lock); - alt_stat = ad_read(devc, 24); - ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ - spin_unlock(&devc->lock); - } - - if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20)) - { - DMAbuf_inputintr(devc->record_dev); - } - if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) && - (alt_stat & 0x10)) - { - DMAbuf_outputintr(devc->playback_dev, 1); - } - if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */ - { - devc->timer_ticks++; -#ifndef EXCLUDE_TIMERS - if (timer_installed == dev && devc->timer_running) - sound_timer_interrupt(); -#endif - } - } -/* - * Sometimes playback or capture interrupts occur while a timer interrupt - * is being handled. The interrupt will not be retriggered if we don't - * handle it now. Check if an interrupt is still pending and restart - * the handler in this case. - */ - if (inb(io_Status(devc)) & 0x01 && cnt++ < 4) - { - goto interrupt_again; - } - return IRQ_HANDLED; -} - -/* - * Experimental initialization sequence for the integrated sound system - * of the Compaq Deskpro M. - */ - -static int init_deskpro_m(struct address_info *hw_config) -{ - unsigned char tmp; - - if ((tmp = inb(0xc44)) == 0xff) - { - DDB(printk("init_deskpro_m: Dead port 0xc44\n")); - return 0; - } - - outb(0x10, 0xc44); - outb(0x40, 0xc45); - outb(0x00, 0xc46); - outb(0xe8, 0xc47); - outb(0x14, 0xc44); - outb(0x40, 0xc45); - outb(0x00, 0xc46); - outb(0xe8, 0xc47); - outb(0x10, 0xc44); - - return 1; -} - -/* - * Experimental initialization sequence for the integrated sound system - * of Compaq Deskpro XL. - */ - -static int init_deskpro(struct address_info *hw_config) -{ - unsigned char tmp; - - if ((tmp = inb(0xc44)) == 0xff) - { - DDB(printk("init_deskpro: Dead port 0xc44\n")); - return 0; - } - outb((tmp | 0x04), 0xc44); /* Select bank 1 */ - if (inb(0xc44) != 0x04) - { - DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n")); - return 0; - } - /* - * OK. It looks like a Deskpro so let's proceed. - */ - - /* - * I/O port 0xc44 Audio configuration register. - * - * bits 0xc0: Audio revision bits - * 0x00 = Compaq Business Audio - * 0x40 = MS Sound System Compatible (reset default) - * 0x80 = Reserved - * 0xc0 = Reserved - * bit 0x20: No Wait State Enable - * 0x00 = Disabled (reset default, DMA mode) - * 0x20 = Enabled (programmed I/O mode) - * bit 0x10: MS Sound System Decode Enable - * 0x00 = Decoding disabled (reset default) - * 0x10 = Decoding enabled - * bit 0x08: FM Synthesis Decode Enable - * 0x00 = Decoding Disabled (reset default) - * 0x08 = Decoding enabled - * bit 0x04 Bank select - * 0x00 = Bank 0 - * 0x04 = Bank 1 - * bits 0x03 MSS Base address - * 0x00 = 0x530 (reset default) - * 0x01 = 0x604 - * 0x02 = 0xf40 - * 0x03 = 0xe80 - */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc44 (before): "); - outb((tmp & ~0x04), 0xc44); - printk("%02x ", inb(0xc44)); - outb((tmp | 0x04), 0xc44); - printk("%02x\n", inb(0xc44)); -#endif - - /* Set bank 1 of the register */ - tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ - - switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0x604: - tmp |= 0x01; - break; - case 0xf40: - tmp |= 0x02; - break; - case 0xe80: - tmp |= 0x03; - break; - default: - DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); - return 0; - } - outb((tmp & ~0x04), 0xc44); /* Write to bank=0 */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc44 (after): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc44)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc44)); -#endif - - /* - * I/O port 0xc45 FM Address Decode/MSS ID Register. - * - * bank=0, bits 0xfe: FM synthesis Decode Compare bits 7:1 (default=0x88) - * bank=0, bit 0x01: SBIC Power Control Bit - * 0x00 = Powered up - * 0x01 = Powered down - * bank=1, bits 0xfc: MSS ID (default=0x40) - */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc45 (before): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc45)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc45)); -#endif - - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb((0x88), 0xc45); /* FM base 7:0 = 0x88 */ - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc45 (after): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc45)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc45)); -#endif - - - /* - * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. - * - * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) - * bank=1, bits 0xff: Audio addressing ASIC id - */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc46 (before): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc46)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc46)); -#endif - - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb((0x03), 0xc46); /* FM base 15:8 = 0x03 */ - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb((0x11), 0xc46); /* ASIC ID = 0x11 */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc46 (after): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc46)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc46)); -#endif - - /* - * I/O port 0xc47 FM Address Decode Register. - * - * bank=0, bits 0xff: Decode enable selection for various FM address bits - * bank=1, bits 0xff: Reserved - */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc47 (before): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc47)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc47)); -#endif - - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb((0x7c), 0xc47); /* FM decode enable bits = 0x7c */ - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb((0x00), 0xc47); /* Reserved bank1 = 0x00 */ - -#ifdef DEBUGXL - /* Debug printing */ - printk("Port 0xc47 (after): "); - outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk("%02x ", inb(0xc47)); - outb((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk("%02x\n", inb(0xc47)); -#endif - - /* - * I/O port 0xc6f = Audio Disable Function Register - */ - -#ifdef DEBUGXL - printk("Port 0xc6f (before) = %02x\n", inb(0xc6f)); -#endif - - outb((0x80), 0xc6f); - -#ifdef DEBUGXL - printk("Port 0xc6f (after) = %02x\n", inb(0xc6f)); -#endif - - return 1; -} - -int probe_ms_sound(struct address_info *hw_config, struct resource *ports) -{ - unsigned char tmp; - - DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); - - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - /* check_opl3(0x388, hw_config); */ - return ad1848_detect(ports, NULL, hw_config->osp); - } - - if (deskpro_xl && hw_config->card_subtype == 2) /* Compaq Deskpro XL */ - { - if (!init_deskpro(hw_config)) - return 0; - } - - if (deskpro_m) /* Compaq Deskpro M */ - { - if (!init_deskpro_m(hw_config)) - return 0; - } - - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00 or 0x0f. - */ - - if ((tmp = inb(hw_config->io_base + 3)) == 0xff) /* Bus float */ - { - int ret; - - DDB(printk("I/O address is inactive (%x)\n", tmp)); - if (!(ret = ad1848_detect(ports, NULL, hw_config->osp))) - return 0; - return 1; - } - DDB(printk("MSS signature = %x\n", tmp & 0x3f)); - if ((tmp & 0x3f) != 0x04 && - (tmp & 0x3f) != 0x0f && - (tmp & 0x3f) != 0x00) - { - int ret; - - MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3))); - DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n")); - if (!(ret = ad1848_detect(ports, NULL, hw_config->osp))) - return 0; - - hw_config->card_subtype = 1; - return 1; - } - if ((hw_config->irq != 5) && - (hw_config->irq != 7) && - (hw_config->irq != 9) && - (hw_config->irq != 10) && - (hw_config->irq != 11) && - (hw_config->irq != 12)) - { - printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma); - return 0; - } - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) - { - printk(KERN_ERR "MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) - { - printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - return 0; - } - return ad1848_detect(ports, NULL, hw_config->osp); -} - -void attach_ms_sound(struct address_info *hw_config, struct resource *ports, struct module *owner) -{ - static signed char interrupt_bits[12] = - { - -1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - signed char bits; - char dma2_bit = 0; - - static char dma_bits[4] = - { - 1, 2, 0, 3 - }; - - int config_port = hw_config->io_base + 0; - int version_port = hw_config->io_base + 3; - int dma = hw_config->dma; - int dma2 = hw_config->dma2; - - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - hw_config->slots[0] = ad1848_init("MS Sound System", ports, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0, - hw_config->osp, - owner); - return; - } - /* - * Set the IRQ and DMA addresses. - */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == -1) - { - printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); - release_region(ports->start, 4); - release_region(ports->start - 4, 4); - return; - } - outb((bits | 0x40), config_port); - if ((inb(version_port) & 0x40) == 0) - printk(KERN_ERR "[MSS: IRQ Conflict?]\n"); - -/* - * Handle the capture DMA channel - */ - - if (dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; - - dma = dma2; - dma2 = tmp; - } - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } - else - { - printk(KERN_WARNING "MSS: Invalid capture DMA\n"); - dma2 = dma; - } - } - else - { - dma2 = dma; - } - - hw_config->dma = dma; - hw_config->dma2 = dma2; - - outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - - hw_config->slots[0] = ad1848_init("MS Sound System", ports, - hw_config->irq, - dma, dma2, 0, - hw_config->osp, - THIS_MODULE); -} - -void unload_ms_sound(struct address_info *hw_config) -{ - ad1848_unload(hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0); - sound_unload_audiodev(hw_config->slots[0]); - release_region(hw_config->io_base, 4); -} - -#ifndef EXCLUDE_TIMERS - -/* - * Timer stuff (for /dev/music). - */ - -static unsigned int current_interval; - -static unsigned int ad1848_tmr_start(int dev, unsigned int usecs) -{ - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ - unsigned long divider; - - spin_lock_irqsave(&devc->lock,flags); - - /* - * Length of the timer interval (in nanoseconds) depends on the - * selected crystal oscillator. Check this from bit 0x01 of I8. - * - * AD1845 has just one oscillator which has cycle time of 10.050 us - * (when a 24.576 MHz xtal oscillator is used). - * - * Convert requested interval to nanoseconds before computing - * the timer divider. - */ - - if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) - xtal_nsecs = 10050; - else if (ad_read(devc, 8) & 0x01) - xtal_nsecs = 9920; - else - xtal_nsecs = 9969; - - divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs; - - if (divider < 100) /* Don't allow shorter intervals than about 1ms */ - divider = 100; - - if (divider > 65535) /* Overflow check */ - divider = 65535; - - ad_write(devc, 21, (divider >> 8) & 0xff); /* Set upper bits */ - ad_write(devc, 20, divider & 0xff); /* Set lower bits */ - ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */ - devc->timer_running = 1; - spin_unlock_irqrestore(&devc->lock,flags); - - return current_interval = (divider * xtal_nsecs + 500) / 1000; -} - -static void ad1848_tmr_reprogram(int dev) -{ - /* - * Audio driver has changed sampling rate so that a different xtal - * oscillator was selected. We have to reprogram the timer rate. - */ - - ad1848_tmr_start(dev, current_interval); - sound_timer_syncinterval(current_interval); -} - -static void ad1848_tmr_disable(int dev) -{ - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - - spin_lock_irqsave(&devc->lock,flags); - ad_write(devc, 16, ad_read(devc, 16) & ~0x40); - devc->timer_running = 0; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void ad1848_tmr_restart(int dev) -{ - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - - if (current_interval == 0) - return; - - spin_lock_irqsave(&devc->lock,flags); - ad_write(devc, 16, ad_read(devc, 16) | 0x40); - devc->timer_running = 1; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static struct sound_lowlev_timer ad1848_tmr = -{ - 0, - 2, - ad1848_tmr_start, - ad1848_tmr_disable, - ad1848_tmr_restart -}; - -static int ad1848_tmr_install(int dev) -{ - if (timer_installed != -1) - return 0; /* Don't install another timer */ - - timer_installed = ad1848_tmr.dev = dev; - sound_timer_init(&ad1848_tmr, audio_devs[dev]->name); - - return 1; -} -#endif /* EXCLUDE_TIMERS */ - -EXPORT_SYMBOL(ad1848_detect); -EXPORT_SYMBOL(ad1848_init); -EXPORT_SYMBOL(ad1848_unload); -EXPORT_SYMBOL(ad1848_control); -EXPORT_SYMBOL(probe_ms_sound); -EXPORT_SYMBOL(attach_ms_sound); -EXPORT_SYMBOL(unload_ms_sound); - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; -static int __initdata type = 0; - -module_param_hw(io, int, ioport, 0); /* I/O for a raw AD1848 card */ -module_param_hw(irq, int, irq, 0); /* IRQ to use */ -module_param_hw(dma, int, dma, 0); /* First DMA channel */ -module_param_hw(dma2, int, dma, 0); /* Second DMA channel */ -module_param(type, int, 0); /* Card type */ -module_param(deskpro_xl, bool, 0); /* Special magic for Deskpro XL boxen */ -module_param(deskpro_m, bool, 0); /* Special magic for Deskpro M box */ -module_param(soundpro, bool, 0); /* More special magic for SoundPro chips */ - -#ifdef CONFIG_PNP -module_param(isapnp, int, 0); -module_param(isapnpjump, int, 0); -module_param(reverse, bool, 0); -MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); -MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); -MODULE_PARM_DESC(reverse, "When set to 1, will reverse ISAPnP search order"); - -static struct pnp_dev *ad1848_dev = NULL; - -/* Please add new entries at the end of the table */ -static struct { - char *name; - unsigned short card_vendor, card_device, - vendor, function; - short mss_io, irq, dma, dma2; /* index into isapnp table */ - int type; -} ad1848_isapnp_list[] __initdata = { - {"CMI 8330 SoundPRO", - ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), - 0, 0, 0,-1, 0}, - {"CS4232 based card", - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0000), - 0, 0, 0, 1, 0}, - {"CS4232 based card", - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), - 0, 0, 0, 1, 0}, - {"OPL3-SA2 WSS mode", - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), - 1, 0, 0, 1, 1}, - {"Advanced Gravis InterWave Audio", - ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), - 0, 0, 0, 1, 0}, - {NULL} -}; - -#ifdef MODULE -static struct isapnp_device_id id_table[] = { - { ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0000), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), 0 }, - /* The main driver for this card is opl3sa2 - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), 0 }, - */ - { ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001), - ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), 0 }, - {0} -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); -#endif - -static struct pnp_dev *activate_dev(char *devname, char *resname, struct pnp_dev *dev) -{ - int err; - - err = pnp_device_attach(dev); - if (err < 0) - return(NULL); - - if((err = pnp_activate_dev(dev)) < 0) { - printk(KERN_ERR "ad1848: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); - - pnp_device_detach(dev); - - return(NULL); - } - audio_activated = 1; - return(dev); -} - -static struct pnp_dev __init *ad1848_init_generic(struct pnp_card *bus, - struct address_info *hw_config, int slot) -{ - - /* Configure Audio device */ - if((ad1848_dev = pnp_find_dev(bus, ad1848_isapnp_list[slot].vendor, ad1848_isapnp_list[slot].function, NULL))) - { - if((ad1848_dev = activate_dev(ad1848_isapnp_list[slot].name, "ad1848", ad1848_dev))) - { - hw_config->io_base = pnp_port_start(ad1848_dev, ad1848_isapnp_list[slot].mss_io); - hw_config->irq = pnp_irq(ad1848_dev, ad1848_isapnp_list[slot].irq); - hw_config->dma = pnp_dma(ad1848_dev, ad1848_isapnp_list[slot].dma); - if(ad1848_isapnp_list[slot].dma2 != -1) - hw_config->dma2 = pnp_dma(ad1848_dev, ad1848_isapnp_list[slot].dma2); - else - hw_config->dma2 = -1; - hw_config->card_subtype = ad1848_isapnp_list[slot].type; - } else - return(NULL); - } else - return(NULL); - - return(ad1848_dev); -} - -static int __init ad1848_isapnp_init(struct address_info *hw_config, struct pnp_card *bus, int slot) -{ - char *busname = bus->name[0] ? bus->name : ad1848_isapnp_list[slot].name; - - /* Initialize this baby. */ - - if(ad1848_init_generic(bus, hw_config, slot)) { - /* We got it. */ - - printk(KERN_NOTICE "ad1848: PnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", - busname, - hw_config->io_base, hw_config->irq, hw_config->dma, - hw_config->dma2); - return 1; - } - return 0; -} - -static int __init ad1848_isapnp_probe(struct address_info *hw_config) -{ - static int first = 1; - int i; - - /* Count entries in sb_isapnp_list */ - for (i = 0; ad1848_isapnp_list[i].card_vendor != 0; i++); - i--; - - /* Check and adjust isapnpjump */ - if( isapnpjump < 0 || isapnpjump > i) { - isapnpjump = reverse ? i : 0; - printk(KERN_ERR "ad1848: Valid range for isapnpjump is 0-%d. Adjusted to %d.\n", i, isapnpjump); - } - - if(!first || !reverse) - i = isapnpjump; - first = 0; - while(ad1848_isapnp_list[i].card_vendor != 0) { - static struct pnp_card *bus = NULL; - - while ((bus = pnp_find_card( - ad1848_isapnp_list[i].card_vendor, - ad1848_isapnp_list[i].card_device, - bus))) { - - if(ad1848_isapnp_init(hw_config, bus, i)) { - isapnpjump = i; /* start next search from here */ - return 0; - } - } - i += reverse ? -1 : 1; - } - - return -ENODEV; -} -#endif - - -static int __init init_ad1848(void) -{ - printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - -#ifdef CONFIG_PNP - if(isapnp && (ad1848_isapnp_probe(&cfg) < 0) ) { - printk(KERN_NOTICE "ad1848: No ISAPnP cards found, trying standard ones...\n"); - isapnp = 0; - } -#endif - - if(io != -1) { - struct resource *ports; - if( isapnp == 0 ) - { - if(irq == -1 || dma == -1) { - printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n"); - return -EINVAL; - } - - cfg.irq = irq; - cfg.io_base = io; - cfg.dma = dma; - cfg.dma2 = dma2; - cfg.card_subtype = type; - } - - ports = request_region(io + 4, 4, "ad1848"); - - if (!ports) - return -EBUSY; - - if (!request_region(io, 4, "WSS config")) { - release_region(io + 4, 4); - return -EBUSY; - } - - if (!probe_ms_sound(&cfg, ports)) { - release_region(io + 4, 4); - release_region(io, 4); - return -ENODEV; - } - attach_ms_sound(&cfg, ports, THIS_MODULE); - loaded = 1; - } - return 0; -} - -static void __exit cleanup_ad1848(void) -{ - if(loaded) - unload_ms_sound(&cfg); - -#ifdef CONFIG_PNP - if(ad1848_dev){ - if(audio_activated) - pnp_device_detach(ad1848_dev); - } -#endif -} - -module_init(init_ad1848); -module_exit(cleanup_ad1848); - -#ifndef MODULE -static int __init setup_ad1848(char *str) -{ - /* io, irq, dma, dma2, type */ - int ints[6]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - type = ints[5]; - - return 1; -} - -__setup("ad1848=", setup_ad1848); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h deleted file mode 100644 index 390f03e13d09..000000000000 --- a/sound/oss/ad1848.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#include <linux/interrupt.h> - -#define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */ -#define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ - -#define AD1848_SET_XTAL 1 -#define AD1848_MIXER_REROUTE 2 - -#define AD1848_REROUTE(oldctl, newctl) \ - ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl)) - - -int ad1848_init(char *name, struct resource *ports, int irq, int dma_playback, - int dma_capture, int share_dma, int *osp, struct module *owner); -void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); - -int ad1848_detect (struct resource *ports, int *flags, int *osp); -int ad1848_control(int cmd, int arg); - -void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner); - -int probe_ms_sound(struct address_info *hw_config, struct resource *ports); -void unload_ms_sound(struct address_info *hw_info); diff --git a/sound/oss/ad1848_mixer.h b/sound/oss/ad1848_mixer.h deleted file mode 100644 index 2cf719b5fbbc..000000000000 --- a/sound/oss/ad1848_mixer.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * sound/oss/ad1848_mixer.h - * - * Definitions for the mixer of AD1848 and compatible codecs. - */ - -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - - -/* - * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. - * Sound card manufacturers have connected actual inputs (CD, synth, line, - * etc) to these inputs in different order. Therefore it's difficult - * to assign mixer channels to these inputs correctly. The following - * contains two alternative mappings. The first one is for GUS MAX and - * the second is just a generic one (line1, line2 and line3). - * (Actually this is not a mapping but rather some kind of interleaving - * solution). - */ -#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE1 | SOUND_MASK_IMIX) - -#define SPRO_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_LINE1) - -#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE2 | \ - SOUND_MASK_IGAIN | \ - SOUND_MASK_PCM | SOUND_MASK_IMIX) - -#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \ - SOUND_MASK_MIC | \ - SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \ - SOUND_MASK_IGAIN | \ - SOUND_MASK_PCM | SOUND_MASK_IMIX) - -#define MODE3_MIXER_DEVICES (MODE2_MIXER_DEVICES | SOUND_MASK_VOLUME) - -/* OPTi 82C930 has no IMIX level control, but it can still be selected as an - * input - */ -#define C930_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \ - SOUND_MASK_MIC | SOUND_MASK_VOLUME | \ - SOUND_MASK_LINE3 | \ - SOUND_MASK_IGAIN | SOUND_MASK_PCM) - -#define SPRO_MIXER_DEVICES (SOUND_MASK_VOLUME | SOUND_MASK_PCM | \ - SOUND_MASK_LINE | SOUND_MASK_SYNTH | \ - SOUND_MASK_CD | SOUND_MASK_MIC | \ - SOUND_MASK_SPEAKER | SOUND_MASK_LINE1 | \ - SOUND_MASK_OGAIN) - -struct mixer_def { - unsigned int regno:6; /* register number for volume */ - unsigned int polarity:1; /* volume polarity: 0=normal, 1=reversed */ - unsigned int bitpos:3; /* position of bits in register for volume */ - unsigned int nbits:3; /* number of bits in register for volume */ - unsigned int mutereg:6; /* register number for mute bit */ - unsigned int mutepol:1; /* mute polarity: 0=normal, 1=reversed */ - unsigned int mutepos:4; /* position of mute bit in register */ - unsigned int recreg:6; /* register number for recording bit */ - unsigned int recpol:1; /* recording polarity: 0=normal, 1=reversed */ - unsigned int recpos:4; /* position of recording bit in register */ -}; - -static char mix_cvt[101] = { - 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, - 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, - 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, - 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, - 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99, - 100 -}; - -typedef struct mixer_def mixer_ent; -typedef mixer_ent mixer_ents[2]; - -/* - * Most of the mixer entries work in backwards. Setting the polarity field - * makes them to work correctly. - * - * The channel numbering used by individual sound cards is not fixed. Some - * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. - * The current version doesn't try to compensate this. - */ - -#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ - [name] = {{reg_l, pola_l, pos_l, len_l, reg_l, 0, mute_bit, 0, 0, 8}, \ - {reg_r, pola_r, pos_r, len_r, reg_r, 0, mute_bit, 0, 0, 8}} - -#define MIX_ENT2(name, reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ - rec_reg_l, rec_pola_l, rec_pos_l, \ - reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ - rec_reg_r, rec_pola_r, rec_pos_r) \ - [name] = {{reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ - rec_reg_l, rec_pola_l, rec_pos_l}, \ - {reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ - rec_reg_r, rec_pola_r, rec_pos_r}} - -static mixer_ents ad1848_mix_devices[32] = { - MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) -}; - -static mixer_ents iwave_mix_devices[32] = { - MIX_ENT(SOUND_MIXER_VOLUME, 25, 1, 0, 5, 27, 1, 0, 5, 8), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_IMIX, 16, 1, 0, 5, 17, 1, 0, 5, 8), - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) -}; - -static mixer_ents cs42xb_mix_devices[32] = { - /* Digital master volume actually has seven bits, but we only use - six to avoid the discontinuity when the analog gain kicks in. */ - MIX_ENT(SOUND_MIXER_VOLUME, 46, 1, 0, 6, 47, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_MIC, 34, 1, 0, 5, 35, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), - /* For the IMIX entry, it was not possible to use the MIX_ENT macro - because the mute bit is in different positions for the two - channels and requires reverse polarity. */ - [SOUND_MIXER_IMIX] = {{13, 1, 2, 6, 13, 1, 0, 0, 0, 8}, - {42, 1, 0, 6, 42, 1, 7, 0, 0, 8}}, - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_LINE3, 38, 1, 0, 6, 39, 1, 0, 6, 7) -}; - -/* OPTi 82C930 has somewhat different port addresses. - * Note: VOLUME == SPEAKER, SYNTH == LINE2, LINE == LINE3, CD == LINE1 - * VOLUME, SYNTH, LINE, CD are not enabled above. - * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc. - */ -static mixer_ents c930_mix_devices[32] = { - MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 1, 5, 23, 1, 1, 5, 7), - MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 5, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 5, 7, 1, 0, 5, 7), - MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 1, 5, 23, 1, 1, 5, 7), - MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_MIC, 20, 1, 1, 4, 21, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), - MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), - MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) -}; - -static mixer_ents spro_mix_devices[32] = { - MIX_ENT (SOUND_MIXER_VOLUME, 19, 0, 4, 4, 19, 0, 0, 4, 8), - MIX_ENT (SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT2(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 23, 0, 3, 0, 0, 8, - 5, 1, 1, 4, 23, 0, 3, 0, 0, 8), - MIX_ENT (SOUND_MIXER_PCM, 6, 1, 1, 4, 7, 1, 1, 4, 8), - MIX_ENT (SOUND_MIXER_SPEAKER, 18, 0, 3, 2, 0, 0, 0, 0, 8), - MIX_ENT2(SOUND_MIXER_LINE, 20, 0, 4, 4, 17, 1, 4, 16, 0, 2, - 20, 0, 0, 4, 17, 1, 3, 16, 0, 1), - MIX_ENT2(SOUND_MIXER_MIC, 18, 0, 0, 3, 17, 1, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - MIX_ENT2(SOUND_MIXER_CD, 21, 0, 4, 4, 17, 1, 2, 16, 0, 4, - 21, 0, 0, 4, 17, 1, 1, 16, 0, 3), - MIX_ENT (SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), - MIX_ENT (SOUND_MIXER_OGAIN, 17, 1, 6, 1, 0, 0, 0, 0, 8), - /* This is external wavetable */ - MIX_ENT2(SOUND_MIXER_LINE1, 22, 0, 4, 4, 23, 1, 1, 23, 0, 4, - 22, 0, 0, 4, 23, 1, 0, 23, 0, 5), -}; - -static int default_mixer_levels[32] = -{ - 0x3232, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x4b4b, /* FM */ - 0x3232, /* PCM */ - 0x1515, /* PC Speaker */ - 0x2020, /* Ext Line */ - 0x1010, /* Mic */ - 0x4b4b, /* CD */ - 0x0000, /* Recording monitor */ - 0x4b4b, /* Second PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ - 0x4b4b, /* Output gain */ - 0x2020, /* Line1 */ - 0x2020, /* Line2 */ - 0x1515 /* Line3 (usually line in)*/ -}; - -#define LEFT_CHN 0 -#define RIGHT_CHN 1 - -/* - * Channel enable bits for ioctl(SOUND_MIXER_PRIVATE1) - */ - -#ifndef AUDIO_SPEAKER -#define AUDIO_SPEAKER 0x01 /* Enable mono output */ -#define AUDIO_HEADPHONE 0x02 /* Sparc only */ -#define AUDIO_LINE_OUT 0x04 /* Sparc only */ -#endif diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c deleted file mode 100644 index f058ed6bdb69..000000000000 --- a/sound/oss/aedsp16.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* - sound/oss/aedsp16.c - - Audio Excel DSP 16 software configuration routines - Copyright (C) 1995,1996,1997,1998 Riccardo Facchetti (fizban@tin.it) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ -/* - * Include the main OSS Lite header file. It include all the os, OSS Lite, etc - * headers needed by this source. - */ -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/init.h> -#include "sound_config.h" - -/* - - READ THIS - - This module started to configure the Audio Excel DSP 16 Sound Card. - Now works with the SC-6000 (old aedsp16) and new SC-6600 based cards. - - NOTE: I have NO idea about Audio Excel DSP 16 III. If someone owns this - audio card and want to see the kernel support for it, please contact me. - - Audio Excel DSP 16 is an SB pro II, Microsoft Sound System and MPU-401 - compatible card. - It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq), - so before this module, the only way to configure the DSP under linux was - boot the MS-DOS loading the sound.sys device driver (this driver soft- - configure the sound board hardware by massaging someone of its registers), - and then ctrl-alt-del to boot linux with the DSP configured by the DOS - driver. - - This module works configuring your Audio Excel DSP 16's irq, dma and - mpu-401-irq. The OSS Lite routines rely on the fact that if the - hardware is there, they can detect it. The problem with AEDSP16 is - that no hardware can be found by the probe routines if the sound card - is not configured properly. Sometimes the kernel probe routines can find - an SBPRO even when the card is not configured (this is the standard setup - of the card), but the SBPRO emulation don't work well if the card is not - properly initialized. For this reason - - aedsp16_init_board() - - routine is called before the OSS Lite probe routines try to detect the - hardware. - - NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS) - - NOTE: Now it works with SC-6000 and SC-6600 based audio cards. The new cards - have no jumper switch at all. No more WSS or MPU-401 I/O port switches. They - have to be configured by software. - - NOTE: The driver is merged with the new OSS Lite sound driver. It works - as a lowlevel driver. - - The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS; - the OSS Lite sound driver can be configured for SBPRO and MSS cards - at the same time, but the aedsp16 can't be two cards!! - When we configure it, we have to choose the SBPRO or the MSS emulation - for AEDSP16. We also can install a *REAL* card of the other type (see [1]). - - NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO - please let me know if it works. - - The MPU-401 support can be compiled in together with one of the other - two operating modes. - - NOTE: This is something like plug-and-play: we have only to plug - the AEDSP16 board in the socket, and then configure and compile - a kernel that uses the AEDSP16 software configuration capability. - No jumper setting is needed! - - For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3 - you have just to make config the OSS Lite package, configuring - the AEDSP16 sound card, then activating the SBPro emulation mode - and at last configuring IRQ and DMA. - Compile the kernel and run it. - - NOTE: This means for SC-6000 cards that you can choose irq and dma, - but not the I/O addresses. To change I/O addresses you have to set - them with jumpers. For SC-6600 cards you have no jumpers so you have - to set up your full card configuration in the make config. - - You can change the irq/dma/mirq settings WITHOUT THE NEED to open - your computer and massage the jumpers (there are no irq/dma/mirq - jumpers to be configured anyway, only I/O BASE values have to be - configured with jumpers) - - For some ununderstandable reason, the card default of irq 7, dma 1, - don't work for me. Seems to be an IRQ or DMA conflict. Under heavy - HDD work, the kernel start to erupt out a lot of messages like: - - 'Sound: DMA timed out - IRQ/DRQ config error?' - - For what I can say, I have NOT any conflict at irq 7 (under linux I'm - using the lp polling driver), and dma line 1 is unused as stated by - /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so - I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows! - Anyway a setting of irq 10, dma 3 works really fine. - - NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know - the emulation mode, all the installed hardware and the hardware - configuration (irq and dma settings of all the hardware). - - This init module should work with SBPRO+MSS, when one of the two is - the AEDSP16 emulation and the other the real card. (see [1]) - For example: - - AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other - AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other - - MPU401 should work. (see [2]) - - [1] - --- - Date: Mon, 29 Jul 1997 08:35:40 +0100 - From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk> - - [...] - Just to let you know got my Audio Excel (emulating a MSS) working - with my original SB16, thanks for the driver! - [...] - --- - - [2] Not tested by me for lack of hardware. - - TODO, WISHES AND TECH - - - About I/O ports allocation - - - Request the 2x0h region (port base) in any case if we are using this card. - - NOTE: the "aedsp16 (base)" string with which we are requesting the aedsp16 - port base region (see code) does not mean necessarily that we are emulating - sbpro. Even if this region is the sbpro I/O ports region, we use this - region to access the control registers of the card, and if emulating - sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro - registers are not used, in no way, to emulate an sbpro: they are - used only for configuration purposes. - - Started Fri Mar 17 16:13:18 MET 1995 - - v0.1 (ALPHA, was a user-level program called AudioExcelDSP16.c) - - Initial code. - v0.2 (ALPHA) - - Cleanups. - - Integrated with Linux voxware v 2.90-2 kernel sound driver. - - SoundBlaster Pro mode configuration. - - Microsoft Sound System mode configuration. - - MPU-401 mode configuration. - v0.3 (ALPHA) - - Cleanups. - - Rearranged the code to let aedsp16_init_board be more general. - - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h - inclusion too. We rely on os.h - - Used the to get a variable - len string (we are not sure about the len of Copyright string). - This works with any SB and compatible. - - Added the code to request_region at device init (should go in - the main body of voxware). - v0.4 (BETA) - - Better configure.c patch for aedsp16 configuration (better - logic of inclusion of AEDSP16 support) - - Modified the conditional compilation to better support more than - one sound card of the emulated type (read the NOTES above) - - Moved the sb init routine from the attach to the very first - probe in sb_card.c - - Rearrangements and cleanups - - Wiped out some unnecessary code and variables: this is kernel - code so it is better save some TEXT and DATA - - Fixed the request_region code. We must allocate the aedsp16 (sbpro) - I/O ports in any case because they are used to access the DSP - configuration registers and we can not allow anyone to get them. - v0.5 - - cleanups on comments - - prep for diffs against v3.0-proto-950402 - v0.6 - - removed the request_region()s when compiling the MODULE sound.o - because we are not allowed (by the actual voxware structure) to - release_region() - v0.7 (pre ALPHA, not distributed) - - started porting this module to kernel 1.3.84. Dummy probe/attach - routines. - v0.8 (ALPHA) - - attached all the init routines. - v0.9 (BETA) - - Integrated with linux-pre2.0.7 - - Integrated with configuration scripts. - - Cleaned up and beautyfied the code. - v0.9.9 (BETA) - - Thanks to Piercarlo Grandi: corrected the conditonal compilation code. - Now only the code configured is compiled in, with some memory saving. - v0.9.10 - - Integration into the sound/lowlevel/ section of the sound driver. - - Re-organized the code. - v0.9.11 (not distributed) - - Rewritten the init interface-routines to initialize the AEDSP16 in - one shot. - - More cosmetics. - - SC-6600 support. - - More soft/hard configuration. - v0.9.12 - - Refined the v0.9.11 code with conditional compilation to distinguish - between SC-6000 and SC-6600 code. - v1.0.0 - - Prep for merging with OSS Lite and Linux kernel 2.1.13 - - Corrected a bug in request/check/release region calls (thanks to the - new kernel exception handling). - v1.1 - - Revamped for integration with new modularized sound drivers: to enhance - the flexibility of modular version, I have removed all the conditional - compilation for SBPRO, MPU and MSS code. Now it is all managed with - the ae_config structure. - v1.2 - - Module informations added. - - Removed aedsp16_delay_10msec(), now using mdelay(10) - - All data and funcs moved to .*.init section. - v1.3 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/27 - - got rid of check_region - - Known Problems: - - Audio Excel DSP 16 III don't work with this driver. - - Credits: - Many thanks to Gerald Britton <gbritton@CapAccess.org>. He helped me a - lot in testing the 0.9.11 and 0.9.12 versions of this driver. - - */ - - -#define VERSION "1.3" /* Version of Audio Excel DSP 16 driver */ - -#undef AEDSP16_DEBUG /* Define this to 1 to enable debug code */ -#undef AEDSP16_DEBUG_MORE /* Define this to 1 to enable more debug */ -#undef AEDSP16_INFO /* Define this to 1 to enable info code */ - -#if defined(AEDSP16_DEBUG) -# define DBG(x) printk x -# if defined(AEDSP16_DEBUG_MORE) -# define DBG1(x) printk x -# else -# define DBG1(x) -# endif -#else -# define DBG(x) -# define DBG1(x) -#endif - -/* - * Misc definitions - */ -#define TRUE 1 -#define FALSE 0 - -/* - * Region Size for request/check/release region. - */ -#define IOBASE_REGION_SIZE 0x10 - -/* - * Hardware related defaults - */ -#define DEF_AEDSP16_IOB 0x220 /* 0x220(default) 0x240 */ -#define DEF_AEDSP16_IRQ 7 /* 5 7(default) 9 10 11 */ -#define DEF_AEDSP16_MRQ 0 /* 5 7 9 10 0(default), 0 means disable */ -#define DEF_AEDSP16_DMA 1 /* 0 1(default) 3 */ - -/* - * Commands of AEDSP16's DSP (SBPRO+special). - * Some of them are COMMAND_xx, in the future they may change. - */ -#define WRITE_MDIRQ_CFG 0x50 /* Set M&I&DRQ mask (the real config) */ -#define COMMAND_52 0x52 /* */ -#define READ_HARD_CFG 0x58 /* Read Hardware Config (I/O base etc) */ -#define COMMAND_5C 0x5c /* */ -#define COMMAND_60 0x60 /* */ -#define COMMAND_66 0x66 /* */ -#define COMMAND_6C 0x6c /* */ -#define COMMAND_6E 0x6e /* */ -#define COMMAND_88 0x88 /* */ -#define DSP_INIT_MSS 0x8c /* Enable Microsoft Sound System mode */ -#define COMMAND_C5 0xc5 /* */ -#define GET_DSP_VERSION 0xe1 /* Get DSP Version */ -#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright */ - -/* - * Offsets of AEDSP16 DSP I/O ports. The offset is added to base I/O port - * to have the actual I/O port. - * Register permissions are: - * (wo) == Write Only - * (ro) == Read Only - * (w-) == Write - * (r-) == Read - */ -#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ -#define DSP_READ 0x0a /* offset of DSP READ (ro) */ -#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ -#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ -#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ -#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ - - -#define RETRY 10 /* Various retry values on I/O opera- */ -#define STATUSRETRY 1000 /* tions. Sometimes we have to */ -#define HARDRETRY 500000 /* wait for previous cmd to complete */ - -/* - * Size of character arrays that store name and version of sound card - */ -#define CARDNAMELEN 15 /* Size of the card's name in chars */ -#define CARDVERLEN 10 /* Size of the card's version in chars */ -#define CARDVERDIGITS 2 /* Number of digits in the version */ - -#if defined(CONFIG_SC6600) -/* - * Bitmapped flags of hard configuration - */ -/* - * Decode macros (xl == low byte, xh = high byte) - */ -#define IOBASE(xl) ((xl & 0x01)?0x240:0x220) -#define JOY(xl) (xl & 0x02) -#define MPUADDR(xl) ( \ - (xl & 0x0C)?0x330: \ - (xl & 0x08)?0x320: \ - (xl & 0x04)?0x310: \ - 0x300) -#define WSSADDR(xl) ((xl & 0x10)?0xE80:0x530) -#define CDROM(xh) (xh & 0x20) -#define CDROMADDR(xh) (((xh & 0x1F) << 4) + 0x200) -/* - * Encode macros - */ -#define BLDIOBASE(xl, val) { \ - xl &= ~0x01; \ - if (val == 0x240) \ - xl |= 0x01; \ - } -#define BLDJOY(xl, val) { \ - xl &= ~0x02; \ - if (val == 1) \ - xl |= 0x02; \ - } -#define BLDMPUADDR(xl, val) { \ - xl &= ~0x0C; \ - switch (val) { \ - case 0x330: \ - xl |= 0x0C; \ - break; \ - case 0x320: \ - xl |= 0x08; \ - break; \ - case 0x310: \ - xl |= 0x04; \ - break; \ - case 0x300: \ - xl |= 0x00; \ - break; \ - default: \ - xl |= 0x00; \ - break; \ - } \ - } -#define BLDWSSADDR(xl, val) { \ - xl &= ~0x10; \ - if (val == 0xE80) \ - xl |= 0x10; \ - } -#define BLDCDROM(xh, val) { \ - xh &= ~0x20; \ - if (val == 1) \ - xh |= 0x20; \ - } -#define BLDCDROMADDR(xh, val) { \ - int tmp = val; \ - tmp -= 0x200; \ - tmp >>= 4; \ - tmp &= 0x1F; \ - xh |= tmp; \ - xh &= 0x7F; \ - xh |= 0x40; \ - } -#endif /* CONFIG_SC6600 */ - -/* - * Bit mapped flags for calling aedsp16_init_board(), and saving the current - * emulation mode. - */ -#define INIT_NONE (0 ) -#define INIT_SBPRO (1<<0) -#define INIT_MSS (1<<1) -#define INIT_MPU401 (1<<2) - -static int soft_cfg __initdata = 0; /* bitmapped config */ -static int soft_cfg_mss __initdata = 0; /* bitmapped mss config */ -static int ver[CARDVERDIGITS] __initdata = {0, 0}; /* DSP Ver: - hi->ver[0] lo->ver[1] */ - -#if defined(CONFIG_SC6600) -static int hard_cfg[2] /* lo<-hard_cfg[0] hi<-hard_cfg[1] */ - __initdata = { 0, 0}; -#endif /* CONFIG_SC6600 */ - -#if defined(CONFIG_SC6600) -/* Decoded hard configuration */ -struct d_hcfg { - int iobase; - int joystick; - int mpubase; - int wssbase; - int cdrom; - int cdrombase; -}; - -static struct d_hcfg decoded_hcfg __initdata = {0, }; - -#endif /* CONFIG_SC6600 */ - -/* orVals contain the values to be or'ed */ -struct orVals { - int val; /* irq|mirq|dma */ - int or; /* soft_cfg |= TheStruct.or */ -}; - -/* aedsp16_info contain the audio card configuration */ -struct aedsp16_info { - int base_io; /* base I/O address for accessing card */ - int irq; /* irq value for DSP I/O */ - int mpu_irq; /* irq for mpu401 interface I/O */ - int dma; /* dma value for DSP I/O */ - int mss_base; /* base I/O for Microsoft Sound System */ - int mpu_base; /* base I/O for MPU-401 emulation */ - int init; /* Initialization status of the card */ -}; - -/* - * Magic values that the DSP will eat when configuring irq/mirq/dma - */ -/* DSP IRQ conversion array */ -static struct orVals orIRQ[] __initdata = { - {0x05, 0x28}, - {0x07, 0x08}, - {0x09, 0x10}, - {0x0a, 0x18}, - {0x0b, 0x20}, - {0x00, 0x00} -}; - -/* MPU-401 IRQ conversion array */ -static struct orVals orMIRQ[] __initdata = { - {0x05, 0x04}, - {0x07, 0x44}, - {0x09, 0x84}, - {0x0a, 0xc4}, - {0x00, 0x00} -}; - -/* DMA Channels conversion array */ -static struct orVals orDMA[] __initdata = { - {0x00, 0x01}, - {0x01, 0x02}, - {0x03, 0x03}, - {0x00, 0x00} -}; - -static struct aedsp16_info ae_config = { - .base_io = DEF_AEDSP16_IOB, - .irq = DEF_AEDSP16_IRQ, - .mpu_irq = DEF_AEDSP16_MRQ, - .dma = DEF_AEDSP16_DMA, - .mss_base = -1, - .mpu_base = -1, - .init = INIT_NONE -}; - -/* - * Buffers to store audio card informations - */ -static char DSPCopyright[CARDNAMELEN + 1] __initdata = {0, }; -static char DSPVersion[CARDVERLEN + 1] __initdata = {0, }; - -static int __init aedsp16_wait_data(int port) -{ - int loop = STATUSRETRY; - unsigned char ret = 0; - - DBG1(("aedsp16_wait_data (0x%x): ", port)); - - do { - ret = inb(port + DSP_DATAVAIL); - /* - * Wait for data available (bit 7 of ret == 1) - */ - } while (!(ret & 0x80) && loop--); - - if (ret & 0x80) { - DBG1(("success.\n")); - return TRUE; - } - - DBG1(("failure.\n")); - return FALSE; -} - -static int __init aedsp16_read(int port) -{ - int inbyte; - - DBG((" Read DSP Byte (0x%x): ", port)); - - if (aedsp16_wait_data(port) == FALSE) { - DBG(("failure.\n")); - return -1; - } - - inbyte = inb(port + DSP_READ); - - DBG(("read [0x%x]/{%c}.\n", inbyte, inbyte)); - - return inbyte; -} - -static int __init aedsp16_test_dsp(int port) -{ - return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE); -} - -static int __init aedsp16_dsp_reset(int port) -{ - /* - * Reset DSP - */ - - DBG(("Reset DSP:\n")); - - outb(1, (port + DSP_RESET)); - udelay(10); - outb(0, (port + DSP_RESET)); - udelay(10); - udelay(10); - if (aedsp16_test_dsp(port) == TRUE) { - DBG(("success.\n")); - return TRUE; - } else - DBG(("failure.\n")); - return FALSE; -} - -static int __init aedsp16_write(int port, int cmd) -{ - unsigned char ret; - int loop = HARDRETRY; - - DBG((" Write DSP Byte (0x%x) [0x%x]: ", port, cmd)); - - do { - ret = inb(port + DSP_STATUS); - /* - * DSP ready to receive data if bit 7 of ret == 0 - */ - if (!(ret & 0x80)) { - outb(cmd, port + DSP_COMMAND); - DBG(("success.\n")); - return 0; - } - } while (loop--); - - DBG(("timeout.\n")); - printk("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd); - - return -1; -} - -#if defined(CONFIG_SC6600) - -#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) -void __init aedsp16_pinfo(void) { - DBG(("\n Base address: %x\n", decoded_hcfg.iobase)); - DBG((" Joystick : %s present\n", decoded_hcfg.joystick?"":" not")); - DBG((" WSS addr : %x\n", decoded_hcfg.wssbase)); - DBG((" MPU-401 addr: %x\n", decoded_hcfg.mpubase)); - DBG((" CDROM : %s present\n", (decoded_hcfg.cdrom!=4)?"":" not")); - DBG((" CDROMADDR : %x\n\n", decoded_hcfg.cdrombase)); -} -#endif - -static void __init aedsp16_hard_decode(void) { - - DBG((" aedsp16_hard_decode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); - -/* - * Decode Cfg Bytes. - */ - decoded_hcfg.iobase = IOBASE(hard_cfg[0]); - decoded_hcfg.joystick = JOY(hard_cfg[0]); - decoded_hcfg.wssbase = WSSADDR(hard_cfg[0]); - decoded_hcfg.mpubase = MPUADDR(hard_cfg[0]); - decoded_hcfg.cdrom = CDROM(hard_cfg[1]); - decoded_hcfg.cdrombase = CDROMADDR(hard_cfg[1]); - -#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) - printk(" Original sound card configuration:\n"); - aedsp16_pinfo(); -#endif - -/* - * Now set up the real kernel configuration. - */ - decoded_hcfg.iobase = ae_config.base_io; - decoded_hcfg.wssbase = ae_config.mss_base; - decoded_hcfg.mpubase = ae_config.mpu_base; - -#if defined(CONFIG_SC6600_JOY) - decoded_hcfg.joystick = CONFIG_SC6600_JOY; /* Enable */ -#endif -#if defined(CONFIG_SC6600_CDROM) - decoded_hcfg.cdrom = CONFIG_SC6600_CDROM; /* 4:N-3:I-2:G-1:P-0:S */ -#endif -#if defined(CONFIG_SC6600_CDROMBASE) - decoded_hcfg.cdrombase = CONFIG_SC6600_CDROMBASE; /* 0 Disable */ -#endif - -#if defined(AEDSP16_DEBUG) - DBG((" New Values:\n")); - aedsp16_pinfo(); -#endif - - DBG(("success.\n")); -} - -static void __init aedsp16_hard_encode(void) { - - DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); - - hard_cfg[0] = 0; - hard_cfg[1] = 0; - - hard_cfg[0] |= 0x20; - - BLDIOBASE (hard_cfg[0], decoded_hcfg.iobase); - BLDWSSADDR(hard_cfg[0], decoded_hcfg.wssbase); - BLDMPUADDR(hard_cfg[0], decoded_hcfg.mpubase); - BLDJOY(hard_cfg[0], decoded_hcfg.joystick); - BLDCDROM(hard_cfg[1], decoded_hcfg.cdrom); - BLDCDROMADDR(hard_cfg[1], decoded_hcfg.cdrombase); - -#if defined(AEDSP16_DEBUG) - aedsp16_pinfo(); -#endif - - DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); - DBG(("success.\n")); - -} - -static int __init aedsp16_hard_write(int port) { - - DBG(("aedsp16_hard_write:\n")); - - if (aedsp16_write(port, COMMAND_6C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6C); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, COMMAND_5C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, hard_cfg[0])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[0]); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, hard_cfg[1])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[1]); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_write(port, COMMAND_C5)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_C5); - DBG(("failure.\n")); - return FALSE; - } - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_hard_read(int port) { - - DBG(("aedsp16_hard_read:\n")); - - if (aedsp16_write(port, READ_HARD_CFG)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - - if ((hard_cfg[0] = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - if ((hard_cfg[1] = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - if (aedsp16_read(port) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - READ_HARD_CFG); - DBG(("failure.\n")); - return FALSE; - } - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_ext_cfg_write(int port) { - - int extcfg, val; - - if (aedsp16_write(port, COMMAND_66)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_66); - return FALSE; - } - - extcfg = 7; - if (decoded_hcfg.cdrom != 2) - extcfg = 0x0F; - if ((decoded_hcfg.cdrom == 4) || - (decoded_hcfg.cdrom == 3)) - extcfg &= ~2; - if (decoded_hcfg.cdrombase == 0) - extcfg &= ~2; - if (decoded_hcfg.mpubase == 0) - extcfg &= ~1; - - if (aedsp16_write(port, extcfg)) { - printk("[AEDSP16] Write extcfg: failed!\n"); - return FALSE; - } - if (aedsp16_write(port, 0)) { - printk("[AEDSP16] Write extcfg: failed!\n"); - return FALSE; - } - if (decoded_hcfg.cdrom == 3) { - if (aedsp16_write(port, COMMAND_52)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52); - return FALSE; - } - if ((val = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n" - , COMMAND_52); - return FALSE; - } - val &= 0x7F; - if (aedsp16_write(port, COMMAND_60)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60); - return FALSE; - } - if (aedsp16_write(port, val)) { - printk("[AEDSP16] Write val: failed!\n"); - return FALSE; - } - } - - return TRUE; -} - -#endif /* CONFIG_SC6600 */ - -static int __init aedsp16_cfg_write(int port) { - if (aedsp16_write(port, WRITE_MDIRQ_CFG)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); - return FALSE; - } - if (aedsp16_write(port, soft_cfg)) { - printk("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n"); - return FALSE; - } - return TRUE; -} - -static int __init aedsp16_init_mss(int port) -{ - DBG(("aedsp16_init_mss:\n")); - - mdelay(10); - - if (aedsp16_write(port, DSP_INIT_MSS)) { - printk("[AEDSP16] aedsp16_init_mss [0x%x]: failed!\n", - DSP_INIT_MSS); - DBG(("failure.\n")); - return FALSE; - } - - mdelay(10); - - if (aedsp16_cfg_write(port) == FALSE) - return FALSE; - - outb(soft_cfg_mss, ae_config.mss_base); - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_setup_board(int port) { - int loop = RETRY; - -#if defined(CONFIG_SC6600) - int val = 0; - - if (aedsp16_hard_read(port) == FALSE) { - printk("[AEDSP16] aedsp16_hard_read: failed!\n"); - return FALSE; - } - - if (aedsp16_write(port, COMMAND_52)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52); - return FALSE; - } - - if ((val = aedsp16_read(port)) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - COMMAND_52); - return FALSE; - } -#endif - - do { - if (aedsp16_write(port, COMMAND_88)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_88); - return FALSE; - } - mdelay(10); - } while ((aedsp16_wait_data(port) == FALSE) && loop--); - - if (aedsp16_read(port) == -1) { - printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n", - COMMAND_88); - return FALSE; - } - -#if !defined(CONFIG_SC6600) - if (aedsp16_write(port, COMMAND_5C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C); - return FALSE; - } -#endif - - if (aedsp16_cfg_write(port) == FALSE) - return FALSE; - -#if defined(CONFIG_SC6600) - if (aedsp16_write(port, COMMAND_60)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60); - return FALSE; - } - if (aedsp16_write(port, val)) { - printk("[AEDSP16] DATA 0x%x: failed!\n", val); - return FALSE; - } - if (aedsp16_write(port, COMMAND_6E)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6E); - return FALSE; - } - if (aedsp16_write(port, ver[0])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", ver[0]); - return FALSE; - } - if (aedsp16_write(port, ver[1])) { - printk("[AEDSP16] DATA 0x%x: failed!\n", ver[1]); - return FALSE; - } - - if (aedsp16_hard_write(port) == FALSE) { - printk("[AEDSP16] aedsp16_hard_write: failed!\n"); - return FALSE; - } - - if (aedsp16_write(port, COMMAND_5C)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C); - return FALSE; - } - -#if defined(THIS_IS_A_THING_I_HAVE_NOT_TESTED_YET) - if (aedsp16_cfg_write(port) == FALSE) - return FALSE; -#endif - -#endif - - return TRUE; -} - -static int __init aedsp16_stdcfg(int port) { - if (aedsp16_write(port, WRITE_MDIRQ_CFG)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); - return FALSE; - } - /* - * 0x0A == (IRQ 7, DMA 1, MIRQ 0) - */ - if (aedsp16_write(port, 0x0A)) { - printk("[AEDSP16] aedsp16_stdcfg: failed!\n"); - return FALSE; - } - return TRUE; -} - -static int __init aedsp16_dsp_version(int port) -{ - int len = 0; - int ret; - - DBG(("Get DSP Version:\n")); - - if (aedsp16_write(ae_config.base_io, GET_DSP_VERSION)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_VERSION); - DBG(("failed.\n")); - return FALSE; - } - - do { - if ((ret = aedsp16_read(port)) == -1) { - DBG(("failed.\n")); - return FALSE; - } - /* - * We already know how many int are stored (2), so we know when the - * string is finished. - */ - ver[len++] = ret; - } while (len < CARDVERDIGITS); - sprintf(DSPVersion, "%d.%d", ver[0], ver[1]); - - DBG(("success.\n")); - - return TRUE; -} - -static int __init aedsp16_dsp_copyright(int port) -{ - int len = 0; - int ret; - - DBG(("Get DSP Copyright:\n")); - - if (aedsp16_write(ae_config.base_io, GET_DSP_COPYRIGHT)) { - printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_COPYRIGHT); - DBG(("failed.\n")); - return FALSE; - } - - do { - if ((ret = aedsp16_read(port)) == -1) { - /* - * If no more data available, return to the caller, no error if len>0. - * We have no other way to know when the string is finished. - */ - if (len) - break; - else { - DBG(("failed.\n")); - return FALSE; - } - } - - DSPCopyright[len++] = ret; - - } while (len < CARDNAMELEN); - - DBG(("success.\n")); - - return TRUE; -} - -static void __init aedsp16_init_tables(void) -{ - int i = 0; - - memset(DSPCopyright, 0, CARDNAMELEN + 1); - memset(DSPVersion, 0, CARDVERLEN + 1); - - for (i = 0; orIRQ[i].or; i++) - if (orIRQ[i].val == ae_config.irq) { - soft_cfg |= orIRQ[i].or; - soft_cfg_mss |= orIRQ[i].or; - } - - for (i = 0; orMIRQ[i].or; i++) - if (orMIRQ[i].or == ae_config.mpu_irq) - soft_cfg |= orMIRQ[i].or; - - for (i = 0; orDMA[i].or; i++) - if (orDMA[i].val == ae_config.dma) { - soft_cfg |= orDMA[i].or; - soft_cfg_mss |= orDMA[i].or; - } -} - -static int __init aedsp16_init_board(void) -{ - aedsp16_init_tables(); - - if (aedsp16_dsp_reset(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_dsp_reset: failed!\n"); - return FALSE; - } - if (aedsp16_dsp_copyright(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_dsp_copyright: failed!\n"); - return FALSE; - } - - /* - * My AEDSP16 card return SC-6000 in DSPCopyright, so - * if we have something different, we have to be warned. - */ - if (strcmp("SC-6000", DSPCopyright)) - printk("[AEDSP16] Warning: non SC-6000 audio card!\n"); - - if (aedsp16_dsp_version(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_dsp_version: failed!\n"); - return FALSE; - } - - if (aedsp16_stdcfg(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_stdcfg: failed!\n"); - return FALSE; - } - -#if defined(CONFIG_SC6600) - if (aedsp16_hard_read(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_hard_read: failed!\n"); - return FALSE; - } - - aedsp16_hard_decode(); - - aedsp16_hard_encode(); - - if (aedsp16_hard_write(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_hard_write: failed!\n"); - return FALSE; - } - - if (aedsp16_ext_cfg_write(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_ext_cfg_write: failed!\n"); - return FALSE; - } -#endif /* CONFIG_SC6600 */ - - if (aedsp16_setup_board(ae_config.base_io) == FALSE) { - printk("[AEDSP16] aedsp16_setup_board: failed!\n"); - return FALSE; - } - - if (ae_config.mss_base != -1) { - if (ae_config.init & INIT_MSS) { - if (aedsp16_init_mss(ae_config.base_io) == FALSE) { - printk("[AEDSP16] Can not initialize" - "Microsoft Sound System mode.\n"); - return FALSE; - } - } - } - -#if !defined(MODULE) || defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) - - printk("Audio Excel DSP 16 init v%s (%s %s) [", - VERSION, DSPCopyright, - DSPVersion); - - if (ae_config.mpu_base != -1) { - if (ae_config.init & INIT_MPU401) { - printk("MPU401"); - if ((ae_config.init & INIT_MSS) || - (ae_config.init & INIT_SBPRO)) - printk(" "); - } - } - - if (ae_config.mss_base == -1) { - if (ae_config.init & INIT_SBPRO) { - printk("SBPro"); - if (ae_config.init & INIT_MSS) - printk(" "); - } - } - - if (ae_config.mss_base != -1) - if (ae_config.init & INIT_MSS) - printk("MSS"); - - printk("]\n"); -#endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */ - - mdelay(10); - - return TRUE; -} - -static int __init init_aedsp16_sb(void) -{ - DBG(("init_aedsp16_sb: ")); - -/* - * If the card is already init'ed MSS, we can not init it to SBPRO too - * because the board can not emulate simultaneously MSS and SBPRO. - */ - if (ae_config.init & INIT_MSS) - return FALSE; - if (ae_config.init & INIT_SBPRO) - return FALSE; - - ae_config.init |= INIT_SBPRO; - - DBG(("done.\n")); - - return TRUE; -} - -static void uninit_aedsp16_sb(void) -{ - DBG(("uninit_aedsp16_sb: ")); - - ae_config.init &= ~INIT_SBPRO; - - DBG(("done.\n")); -} - -static int __init init_aedsp16_mss(void) -{ - DBG(("init_aedsp16_mss: ")); - -/* - * If the card is already init'ed SBPRO, we can not init it to MSS too - * because the board can not emulate simultaneously MSS and SBPRO. - */ - if (ae_config.init & INIT_SBPRO) - return FALSE; - if (ae_config.init & INIT_MSS) - return FALSE; -/* - * We must allocate the CONFIG_AEDSP16_BASE region too because these are the - * I/O ports to access card's control registers. - */ - if (!(ae_config.init & INIT_MPU401)) { - if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE, - "aedsp16 (base)")) { - printk( - "AEDSP16 BASE I/O port region is already in use.\n"); - return FALSE; - } - } - - ae_config.init |= INIT_MSS; - - DBG(("done.\n")); - - return TRUE; -} - -static void uninit_aedsp16_mss(void) -{ - DBG(("uninit_aedsp16_mss: ")); - - if ((!(ae_config.init & INIT_MPU401)) && - (ae_config.init & INIT_MSS)) { - release_region(ae_config.base_io, IOBASE_REGION_SIZE); - DBG(("AEDSP16 base region released.\n")); - } - - ae_config.init &= ~INIT_MSS; - DBG(("done.\n")); -} - -static int __init init_aedsp16_mpu(void) -{ - DBG(("init_aedsp16_mpu: ")); - - if (ae_config.init & INIT_MPU401) - return FALSE; - -/* - * We must request the CONFIG_AEDSP16_BASE region too because these are the I/O - * ports to access card's control registers. - */ - if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) { - if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE, - "aedsp16 (base)")) { - printk( - "AEDSP16 BASE I/O port region is already in use.\n"); - return FALSE; - } - } - - ae_config.init |= INIT_MPU401; - - DBG(("done.\n")); - - return TRUE; -} - -static void uninit_aedsp16_mpu(void) -{ - DBG(("uninit_aedsp16_mpu: ")); - - if ((!(ae_config.init & (INIT_MSS | INIT_SBPRO))) && - (ae_config.init & INIT_MPU401)) { - release_region(ae_config.base_io, IOBASE_REGION_SIZE); - DBG(("AEDSP16 base region released.\n")); - } - - ae_config.init &= ~INIT_MPU401; - - DBG(("done.\n")); -} - -static int __init init_aedsp16(void) -{ - int initialized = FALSE; - - DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n", - ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq)); - - if (ae_config.mss_base == -1) { - if (init_aedsp16_sb() == FALSE) { - uninit_aedsp16_sb(); - } else { - initialized = TRUE; - } - } - - if (ae_config.mpu_base != -1) { - if (init_aedsp16_mpu() == FALSE) { - uninit_aedsp16_mpu(); - } else { - initialized = TRUE; - } - } - -/* - * In the sequence of init routines, the MSS init MUST be the last! - * This because of the special register programming the MSS mode needs. - * A board reset would disable the MSS mode restoring the default SBPRO - * mode. - */ - if (ae_config.mss_base != -1) { - if (init_aedsp16_mss() == FALSE) { - uninit_aedsp16_mss(); - } else { - initialized = TRUE; - } - } - - if (initialized) - initialized = aedsp16_init_board(); - return initialized; -} - -static void __exit uninit_aedsp16(void) -{ - if (ae_config.mss_base != -1) - uninit_aedsp16_mss(); - else - uninit_aedsp16_sb(); - if (ae_config.mpu_base != -1) - uninit_aedsp16_mpu(); -} - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata mpu_irq = -1; -static int __initdata mss_base = -1; -static int __initdata mpu_base = -1; - -module_param_hw(io, int, ioport, 0); -MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)"); -module_param_hw(irq, int, irq, 0); -MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)"); -module_param_hw(dma, int, dma, 0); -MODULE_PARM_DESC(dma, "dma line (0 1 3)"); -module_param_hw(mpu_irq, int, irq, 0); -MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)"); -module_param_hw(mss_base, int, ioport, 0); -MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)"); -module_param_hw(mpu_base, int, ioport, 0); -MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)"); -MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>"); -MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION); -MODULE_LICENSE("GPL"); - -static int __init do_init_aedsp16(void) { - printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n"); - if (io == -1 || dma == -1 || irq == -1) { - printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n"); - return -EINVAL; - } - - ae_config.base_io = io; - ae_config.irq = irq; - ae_config.dma = dma; - - ae_config.mss_base = mss_base; - ae_config.mpu_base = mpu_base; - ae_config.mpu_irq = mpu_irq; - - if (init_aedsp16() == FALSE) { - printk(KERN_ERR "aedsp16: initialization failed\n"); - /* - * XXX - * What error should we return here ? - */ - return -EINVAL; - } - return 0; -} - -static void __exit cleanup_aedsp16(void) { - uninit_aedsp16(); -} - -module_init(do_init_aedsp16); -module_exit(cleanup_aedsp16); - -#ifndef MODULE -static int __init setup_aedsp16(char *str) -{ - /* io, irq, dma, mss_io, mpu_io, mpu_irq */ - int ints[7]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - mss_base = ints[4]; - mpu_base = ints[5]; - mpu_irq = ints[6]; - return 1; -} - -__setup("aedsp16=", setup_aedsp16); -#endif diff --git a/sound/oss/audio.c b/sound/oss/audio.c deleted file mode 100644 index 09c932f899b8..000000000000 --- a/sound/oss/audio.c +++ /dev/null @@ -1,985 +0,0 @@ -/* - * sound/oss/audio.c - * - * Device file manager for /dev/audio - */ - -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Thomas Sailer : moved several static variables into struct audio_operations - * (which is grossly misnamed btw.) because they have the same - * lifetime as the rest in there and dynamic allocation saves - * 12k or so - * Thomas Sailer : use more logical O_NONBLOCK semantics - * Daniel Rodriksson: reworked the use of the device specific copy_user - * still generic - * Horst von Brand: Add missing #include <linux/string.h> - * Chris Rankin : Update the module-usage counter for the coprocessor, - * and decrement the counters again if we cannot open - * the audio device. - */ - -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/kmod.h> - -#include "sound_config.h" -#include "ulaw.h" -#include "coproc.h" - -#define NEUTRAL8 0x80 -#define NEUTRAL16 0x00 - - -static int dma_ioctl(int dev, unsigned int cmd, void __user *arg); - -static int set_format(int dev, int fmt) -{ - if (fmt != AFMT_QUERY) - { - audio_devs[dev]->local_conversion = 0; - - if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ - { - if (fmt == AFMT_MU_LAW) - { - fmt = AFMT_U8; - audio_devs[dev]->local_conversion = CNV_MU_LAW; - } - else - fmt = AFMT_U8; /* This is always supported */ - } - audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt); - audio_devs[dev]->local_format = fmt; - } - else - return audio_devs[dev]->local_format; - - if (audio_devs[dev]->local_conversion) - return audio_devs[dev]->local_conversion; - else - return audio_devs[dev]->local_format; -} - -int audio_open(int dev, struct file *file) -{ - int ret; - int bits; - int dev_type = dev & 0x0f; - int mode = translate_mode(file); - const struct audio_driver *driver; - const struct coproc_operations *coprocessor; - - dev = dev >> 4; - - if (dev_type == SND_DEV_DSP16) - bits = 16; - else - bits = 8; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - driver = audio_devs[dev]->d; - - if (!try_module_get(driver->owner)) - return -ENODEV; - - if ((ret = DMAbuf_open(dev, mode)) < 0) - goto error_1; - - if ( (coprocessor = audio_devs[dev]->coproc) != NULL ) { - if (!try_module_get(coprocessor->owner)) - goto error_2; - - if ((ret = coprocessor->open(coprocessor->devc, COPR_PCM)) < 0) { - printk(KERN_WARNING "Sound: Can't access coprocessor device\n"); - goto error_3; - } - } - - audio_devs[dev]->local_conversion = 0; - - if (dev_type == SND_DEV_AUDIO) - set_format(dev, AFMT_MU_LAW); - else - set_format(dev, bits); - - audio_devs[dev]->audio_mode = AM_NONE; - - return 0; - - /* - * Clean-up stack: this is what needs (un)doing if - * we can't open the audio device ... - */ - error_3: - module_put(coprocessor->owner); - - error_2: - DMAbuf_release(dev, mode); - - error_1: - module_put(driver->owner); - - return ret; -} - -static void sync_output(int dev) -{ - int p, i; - int l; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->fragment_size <= 0) - return; - dmap->flags |= DMA_POST; - - /* Align the write pointer with fragment boundaries */ - - if ((l = dmap->user_counter % dmap->fragment_size) > 0) - { - int len; - unsigned long offs = dmap->user_counter % dmap->bytes_in_use; - - len = dmap->fragment_size - l; - memset(dmap->raw_buf + offs, dmap->neutral_byte, len); - DMAbuf_move_wrpointer(dev, len); - } - - /* - * Clean all unused buffer fragments. - */ - - p = dmap->qtail; - dmap->flags |= DMA_POST; - - for (i = dmap->qlen + 1; i < dmap->nbufs; i++) - { - p = (p + 1) % dmap->nbufs; - if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > - (dmap->raw_buf + dmap->buffsize)) - printk(KERN_ERR "audio: Buffer error 2\n"); - - memset(dmap->raw_buf + p * dmap->fragment_size, - dmap->neutral_byte, - dmap->fragment_size); - } - - dmap->flags |= DMA_DIRTY; -} - -void audio_release(int dev, struct file *file) -{ - const struct coproc_operations *coprocessor; - int mode = translate_mode(file); - - dev = dev >> 4; - - /* - * We do this in DMAbuf_release(). Why are we doing it - * here? Why don't we test the file mode before setting - * both flags? DMAbuf_release() does. - * ...pester...pester...pester... - */ - audio_devs[dev]->dmap_out->closing = 1; - audio_devs[dev]->dmap_in->closing = 1; - - /* - * We need to make sure we allocated the dmap_out buffer - * before we go mucking around with it in sync_output(). - */ - if (mode & OPEN_WRITE) - sync_output(dev); - - if ( (coprocessor = audio_devs[dev]->coproc) != NULL ) { - coprocessor->close(coprocessor->devc, COPR_PCM); - module_put(coprocessor->owner); - } - DMAbuf_release(dev, mode); - - module_put(audio_devs[dev]->d->owner); -} - -static void translate_bytes(const unsigned char *table, unsigned char *buff, int n) -{ - unsigned long i; - - if (n <= 0) - return; - - for (i = 0; i < n; ++i) - buff[i] = table[buff[i]]; -} - -int audio_write(int dev, struct file *file, const char __user *buf, int count) -{ - int c, p, l, buf_size, used, returned; - int err; - char *dma_buf; - - dev = dev >> 4; - - p = 0; - c = count; - - if(count < 0) - return -EINVAL; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_devs[dev]->audio_mode |= AM_WRITE; - else - audio_devs[dev]->audio_mode = AM_WRITE; - - if (!count) /* Flush output */ - { - sync_output(dev); - return 0; - } - - while (c) - { - if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, !!(file->f_flags & O_NONBLOCK))) < 0) - { - /* Handle nonblocking mode */ - if ((file->f_flags & O_NONBLOCK) && err == -EAGAIN) - return p? p : -EAGAIN; /* No more space. Return # of accepted bytes */ - return err; - } - l = c; - - if (l > buf_size) - l = buf_size; - - returned = l; - used = l; - if (!audio_devs[dev]->d->copy_user) - { - if ((dma_buf + l) > - (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) - { - printk(KERN_ERR "audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize); - return -EDOM; - } - if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) - { - printk(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf); - return -EDOM; - } - if(copy_from_user(dma_buf, &(buf)[p], l)) - return -EFAULT; - } - else audio_devs[dev]->d->copy_user (dev, - dma_buf, 0, - buf, p, - c, buf_size, - &used, &returned, - l); - l = returned; - - if (audio_devs[dev]->local_conversion & CNV_MU_LAW) - { - translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); - } - c -= used; - p += used; - DMAbuf_move_wrpointer(dev, l); - - } - - return count; -} - -int audio_read(int dev, struct file *file, char __user *buf, int count) -{ - int c, p, l; - char *dmabuf; - int buf_no; - - dev = dev >> 4; - p = 0; - c = count; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EPERM; - - if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - sync_output(dev); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_devs[dev]->audio_mode |= AM_READ; - else - audio_devs[dev]->audio_mode = AM_READ; - - while(c) - { - if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, !!(file->f_flags & O_NONBLOCK))) < 0) - { - /* - * Nonblocking mode handling. Return current # of bytes - */ - - if (p > 0) /* Avoid throwing away data */ - return p; /* Return it instead */ - - if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN) - return -EAGAIN; - - return buf_no; - } - if (l > c) - l = c; - - /* - * Insert any local processing here. - */ - - if (audio_devs[dev]->local_conversion & CNV_MU_LAW) - { - translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l); - } - - { - char *fixit = dmabuf; - - if(copy_to_user(&(buf)[p], fixit, l)) - return -EFAULT; - } - - DMAbuf_rmchars(dev, buf_no, l); - - p += l; - c -= l; - } - - return count - c; -} - -int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) -{ - int val, count; - unsigned long flags; - struct dma_buffparms *dmap; - int __user *p = arg; - - dev = dev >> 4; - - if (_IOC_TYPE(cmd) == 'C') { - if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ - return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); - /* else - printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */ - return -ENXIO; - } - else switch (cmd) - { - case SNDCTL_DSP_SYNC: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - if (audio_devs[dev]->dmap_out->fragment_size == 0) - return 0; - sync_output(dev); - DMAbuf_sync(dev); - DMAbuf_reset(dev); - return 0; - - case SNDCTL_DSP_POST: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - if (audio_devs[dev]->dmap_out->fragment_size == 0) - return 0; - audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; - sync_output(dev); - dma_ioctl(dev, SNDCTL_DSP_POST, NULL); - return 0; - - case SNDCTL_DSP_RESET: - audio_devs[dev]->audio_mode = AM_NONE; - DMAbuf_reset(dev); - return 0; - - case SNDCTL_DSP_GETFMTS: - val = audio_devs[dev]->format_mask | AFMT_MU_LAW; - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - val = set_format(dev, val); - break; - - case SNDCTL_DSP_GETISPACE: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - return dma_ioctl(dev, cmd, arg); - - case SNDCTL_DSP_GETOSPACE: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - return dma_ioctl(dev, cmd, arg); - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETCAPS: - val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode == OPEN_READWRITE) - val |= DSP_CAP_DUPLEX; - if (audio_devs[dev]->coproc) - val |= DSP_CAP_COPROC; - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - val |= DSP_CAP_BATCH; - if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ - val |= DSP_CAP_TRIGGER; - break; - - case SOUND_PCM_WRITE_RATE: - if (get_user(val, p)) - return -EFAULT; - val = audio_devs[dev]->d->set_speed(dev, val); - break; - - case SOUND_PCM_READ_RATE: - val = audio_devs[dev]->d->set_speed(dev, 0); - break; - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - if (val > 1 || val < 0) - return -EINVAL; - val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - val = audio_devs[dev]->d->set_channels(dev, val); - break; - - case SOUND_PCM_READ_CHANNELS: - val = audio_devs[dev]->d->set_channels(dev, 0); - break; - - case SOUND_PCM_READ_BITS: - val = audio_devs[dev]->d->set_bits(dev, 0); - break; - - case SNDCTL_DSP_SETDUPLEX: - if (audio_devs[dev]->open_mode != OPEN_READWRITE) - return -EPERM; - return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; - - case SNDCTL_DSP_PROFILE: - if (get_user(val, p)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->applic_profile = val; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->applic_profile = val; - return 0; - - case SNDCTL_DSP_GETODELAY: - dmap = audio_devs[dev]->dmap_out; - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (!(dmap->flags & DMA_ALLOC_DONE)) - { - val=0; - break; - } - - spin_lock_irqsave(&dmap->lock,flags); - /* Compute number of bytes that have been played */ - count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - if (count < dmap->fragment_size && dmap->qhead != 0) - count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - count += dmap->byte_counter; - - /* Subtract current count from the number of bytes written by app */ - count = dmap->user_counter - count; - if (count < 0) - count = 0; - spin_unlock_irqrestore(&dmap->lock,flags); - val = count; - break; - - default: - return dma_ioctl(dev, cmd, arg); - } - return put_user(val, p); -} - -void audio_init_devices(void) -{ - /* - * NOTE! This routine could be called several times during boot. - */ -} - -void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) -{ - /* - * This routine breaks the physical device buffers to logical ones. - */ - - struct audio_operations *dsp_dev = audio_devs[dev]; - - unsigned i, n; - unsigned sr, nc, sz, bsz; - - sr = dsp_dev->d->set_speed(dev, 0); - nc = dsp_dev->d->set_channels(dev, 0); - sz = dsp_dev->d->set_bits(dev, 0); - - if (sz == 8) - dmap->neutral_byte = NEUTRAL8; - else - dmap->neutral_byte = NEUTRAL16; - - if (sr < 1 || nc < 1 || sz < 1) - { -/* printk(KERN_DEBUG "Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);*/ - sr = DSP_DEFAULT_SPEED; - nc = 1; - sz = 8; - } - - sz = sr * nc * sz; - - sz /= 8; /* #bits -> #bytes */ - dmap->data_rate = sz; - - if (!dmap->needs_reorg) - return; - dmap->needs_reorg = 0; - - if (dmap->fragment_size == 0) - { - /* Compute the fragment size using the default algorithm */ - - /* - * Compute a buffer size for time not exceeding 1 second. - * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds - * of sound (using the current speed, sample size and #channels). - */ - - bsz = dmap->buffsize; - while (bsz > sz) - bsz /= 2; - - if (bsz == dmap->buffsize) - bsz /= 2; /* Needs at least 2 buffers */ - - /* - * Split the computed fragment to smaller parts. After 3.5a9 - * the default subdivision is 4 which should give better - * results when recording. - */ - - if (dmap->subdivision == 0) /* Not already set */ - { - dmap->subdivision = 4; /* Init to the default value */ - - if ((bsz / dmap->subdivision) > 4096) - dmap->subdivision *= 2; - if ((bsz / dmap->subdivision) < 4096) - dmap->subdivision = 1; - } - bsz /= dmap->subdivision; - - if (bsz < 16) - bsz = 16; /* Just a sanity check */ - - dmap->fragment_size = bsz; - } - else - { - /* - * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or - * the buffer size computation has already been done. - */ - if (dmap->fragment_size > (dmap->buffsize / 2)) - dmap->fragment_size = (dmap->buffsize / 2); - bsz = dmap->fragment_size; - } - - if (audio_devs[dev]->min_fragment) - if (bsz < (1 << audio_devs[dev]->min_fragment)) - bsz = 1 << audio_devs[dev]->min_fragment; - if (audio_devs[dev]->max_fragment) - if (bsz > (1 << audio_devs[dev]->max_fragment)) - bsz = 1 << audio_devs[dev]->max_fragment; - bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ -#ifdef OS_DMA_ALIGN_CHECK - OS_DMA_ALIGN_CHECK(bsz); -#endif - - n = dmap->buffsize / bsz; - if (n > MAX_SUB_BUFFERS) - n = MAX_SUB_BUFFERS; - if (n > dmap->max_fragments) - n = dmap->max_fragments; - - if (n < 2) - { - n = 2; - bsz /= 2; - } - dmap->nbufs = n; - dmap->bytes_in_use = n * bsz; - dmap->fragment_size = bsz; - dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + - dmap->bytes_in_use; /* Approximately one hour */ - - if (dmap->raw_buf) - { - memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); - } - - for (i = 0; i < dmap->nbufs; i++) - { - dmap->counts[i] = 0; - } - - dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; -} - -static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact) -{ - if (fact == 0) - { - fact = dmap->subdivision; - if (fact == 0) - fact = 1; - return fact; - } - if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ - return -EINVAL; - - if (fact > MAX_REALTIME_FACTOR) - return -EINVAL; - - if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return -EINVAL; - - dmap->subdivision = fact; - return fact; -} - -static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact) -{ - int bytes, count; - - if (fact == 0) - return -EIO; - - if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; - - bytes = fact & 0xffff; - count = (fact >> 16) & 0x7fff; - - if (count == 0) - count = MAX_SUB_BUFFERS; - else if (count < MAX_SUB_BUFFERS) - count++; - - if (bytes < 4 || bytes > 17) /* <16 || > 512k */ - return -EINVAL; - - if (count < 2) - return -EINVAL; - - if (audio_devs[dev]->min_fragment > 0) - if (bytes < audio_devs[dev]->min_fragment) - bytes = audio_devs[dev]->min_fragment; - - if (audio_devs[dev]->max_fragment > 0) - if (bytes > audio_devs[dev]->max_fragment) - bytes = audio_devs[dev]->max_fragment; - -#ifdef OS_DMA_MINBITS - if (bytes < OS_DMA_MINBITS) - bytes = OS_DMA_MINBITS; -#endif - - dmap->fragment_size = (1 << bytes); - dmap->max_fragments = count; - - if (dmap->fragment_size > dmap->buffsize) - dmap->fragment_size = dmap->buffsize; - - if (dmap->fragment_size == dmap->buffsize && - audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->fragment_size /= 2; /* Needs at least 2 buffers */ - - dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - return bytes | ((count - 1) << 16); -} - -static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; - struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; - struct dma_buffparms *dmap; - audio_buf_info info; - count_info cinfo; - int fact, ret, changed, bits, count, err; - unsigned long flags; - - switch (cmd) - { - case SNDCTL_DSP_SUBDIVIDE: - ret = 0; - if (get_user(fact, (int __user *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_subdivide(dev, dmap_out, fact); - if (ret < 0) - return ret; - if (audio_devs[dev]->open_mode != OPEN_WRITE || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_subdivide(dev, dmap_in, fact); - if (ret < 0) - return ret; - break; - - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_GETOSPACE: - dmap = dmap_out; - if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) - dmap = dmap_in; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -EINVAL; - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); - info.fragstotal = dmap->nbufs; - if (cmd == SNDCTL_DSP_GETISPACE) - info.fragments = dmap->qlen; - else - { - if (!DMAbuf_space_in_queue(dev)) - info.fragments = 0; - else - { - info.fragments = DMAbuf_space_in_queue(dev); - if (audio_devs[dev]->d->local_qlen) - { - int tmp = audio_devs[dev]->d->local_qlen(dev); - if (tmp && info.fragments) - tmp--; /* - * This buffer has been counted twice - */ - info.fragments -= tmp; - } - } - } - if (info.fragments < 0) - info.fragments = 0; - else if (info.fragments > dmap->nbufs) - info.fragments = dmap->nbufs; - - info.fragsize = dmap->fragment_size; - info.bytes = info.fragments * dmap->fragment_size; - - if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) - info.bytes -= dmap->counts[dmap->qhead]; - else - { - info.fragments = info.bytes / dmap->fragment_size; - info.bytes -= dmap->user_counter % dmap->fragment_size; - } - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(bits, (int __user *)arg)) - return -EFAULT; - bits &= audio_devs[dev]->open_mode; - if (audio_devs[dev]->d->trigger == NULL) - return -EINVAL; - if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && - (bits & PCM_ENABLE_OUTPUT)) - return -EINVAL; - - if (bits & PCM_ENABLE_INPUT) - { - spin_lock_irqsave(&dmap_in->lock,flags); - changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_INPUT; - if (changed && audio_devs[dev]->go) - { - reorganize_buffers(dev, dmap_in, 1); - if ((err = audio_devs[dev]->d->prepare_for_input(dev, - dmap_in->fragment_size, dmap_in->nbufs)) < 0) { - spin_unlock_irqrestore(&dmap_in->lock,flags); - return err; - } - dmap_in->dma_mode = DMODE_INPUT; - audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; - DMAbuf_activate_recording(dev, dmap_in); - } else - audio_devs[dev]->enable_bits &= ~PCM_ENABLE_INPUT; - spin_unlock_irqrestore(&dmap_in->lock,flags); - } - if (bits & PCM_ENABLE_OUTPUT) - { - spin_lock_irqsave(&dmap_out->lock,flags); - changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_OUTPUT; - if (changed && - (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && - audio_devs[dev]->go) - { - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap_out, 0); - dmap_out->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->enable_bits |= PCM_ENABLE_OUTPUT; - dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; - DMAbuf_launch_output(dev, dmap_out); - } else - audio_devs[dev]->enable_bits &= ~PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&dmap_out->lock,flags); - } -#if 0 - if (changed && audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); -#endif - /* Falls through... */ - - case SNDCTL_DSP_GETTRIGGER: - ret = audio_devs[dev]->enable_bits; - break; - - case SNDCTL_DSP_SETSYNCRO: - if (!audio_devs[dev]->d->trigger) - return -EINVAL; - audio_devs[dev]->d->trigger(dev, 0); - audio_devs[dev]->go = 0; - return 0; - - case SNDCTL_DSP_GETIPTR: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - spin_lock_irqsave(&dmap_in->lock,flags); - cinfo.bytes = dmap_in->byte_counter; - cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; - if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) - cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */ - cinfo.blocks = dmap_in->qlen; - cinfo.bytes += cinfo.ptr; - if (dmap_in->mapping_flags & DMA_MAP_MAPPED) - dmap_in->qlen = 0; /* Reset interrupt counter */ - spin_unlock_irqrestore(&dmap_in->lock,flags); - if (copy_to_user(arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - - spin_lock_irqsave(&dmap_out->lock,flags); - cinfo.bytes = dmap_out->byte_counter; - cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; - if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) - cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ - cinfo.blocks = dmap_out->qlen; - cinfo.bytes += cinfo.ptr; - if (dmap_out->mapping_flags & DMA_MAP_MAPPED) - dmap_out->qlen = 0; /* Reset interrupt counter */ - spin_unlock_irqrestore(&dmap_out->lock,flags); - if (copy_to_user(arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - { - ret=0; - break; - } - spin_lock_irqsave(&dmap_out->lock,flags); - /* Compute number of bytes that have been played */ - count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); - if (count < dmap_out->fragment_size && dmap_out->qhead != 0) - count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ - count += dmap_out->byte_counter; - /* Subtract current count from the number of bytes written by app */ - count = dmap_out->user_counter - count; - if (count < 0) - count = 0; - spin_unlock_irqrestore(&dmap_out->lock,flags); - ret = count; - break; - - case SNDCTL_DSP_POST: - if (audio_devs[dev]->dmap_out->qlen > 0) - if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) - DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - dmap = dmap_out; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode == OPEN_READ) - dmap = dmap_in; - ret = dmap->fragment_size; - break; - - case SNDCTL_DSP_SETFRAGMENT: - ret = 0; - if (get_user(fact, (int __user *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_set_fragment(dev, dmap_out, fact); - if (ret < 0) - return ret; - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_set_fragment(dev, dmap_in, fact); - if (ret < 0) - return ret; - if (!arg) /* don't know what this is good for, but preserve old semantics */ - return 0; - break; - - default: - if (!audio_devs[dev]->d->ioctl) - return -EINVAL; - return audio_devs[dev]->d->ioctl(dev, cmd, arg); - } - return put_user(ret, (int __user *)arg); -} diff --git a/sound/oss/bin2hex.c b/sound/oss/bin2hex.c deleted file mode 100644 index 26c04ce04d71..000000000000 --- a/sound/oss/bin2hex.c +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -int main( int argc, const char * argv [] ) -{ - const char * varname; - int i = 0; - int c; - int id = 0; - - if(argv[1] && strcmp(argv[1],"-i")==0) - { - argv++; - argc--; - id=1; - } - - if(argc==1) - { - fprintf(stderr, "bin2hex: [-i] firmware\n"); - exit(1); - } - - varname = argv[1]; - printf( "/* automatically generated by bin2hex */\n" ); - printf( "static unsigned char %s [] %s =\n{\n", varname , id?"__initdata":""); - - while ( ( c = getchar( ) ) != EOF ) - { - if ( i != 0 && i % 10 == 0 ) - printf( "\n" ); - printf( "0x%02lx,", c & 0xFFl ); - i++; - } - - printf( "};\nstatic int %sLen = %d;\n", varname, i ); - return 0; -} diff --git a/sound/oss/coproc.h b/sound/oss/coproc.h deleted file mode 100644 index 7bec21bbdd88..000000000000 --- a/sound/oss/coproc.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Definitions for various on board processors on the sound cards. For - * example DSP processors. - */ - -/* - * Coprocessor access types - */ -#define COPR_CUSTOM 0x0001 /* Custom applications */ -#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */ -#define COPR_PCM 0x0004 /* Digitized voice applications */ -#define COPR_SYNTH 0x0008 /* Music synthesis */ diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c deleted file mode 100644 index 6dad51596b70..000000000000 --- a/sound/oss/dev_table.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * sound/oss/dev_table.c - * - * Device call tables. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - -#include <linux/init.h> - -#include "sound_config.h" - -struct audio_operations *audio_devs[MAX_AUDIO_DEV]; -EXPORT_SYMBOL(audio_devs); - -int num_audiodevs; -EXPORT_SYMBOL(num_audiodevs); - -struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; -EXPORT_SYMBOL(mixer_devs); - -int num_mixers; -EXPORT_SYMBOL(num_mixers); - -struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; -EXPORT_SYMBOL(synth_devs); - -int num_synths; - -struct midi_operations *midi_devs[MAX_MIDI_DEV]; -EXPORT_SYMBOL(midi_devs); - -int num_midis; -EXPORT_SYMBOL(num_midis); - -struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { - &default_sound_timer, NULL -}; -EXPORT_SYMBOL(sound_timer_devs); - -int num_sound_timers = 1; - - -static int sound_alloc_audiodev(void); - -int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, - int driver_size, int flags, unsigned int format_mask, - void *devc, int dma1, int dma2) -{ - struct audio_driver *d; - struct audio_operations *op; - int num; - - if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) { - printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name); - return -EINVAL; - } - num = sound_alloc_audiodev(); - - if (num == -1) { - printk(KERN_ERR "sound: Too many audio drivers\n"); - return -EBUSY; - } - d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver))); - sound_nblocks++; - if (sound_nblocks >= MAX_MEM_BLOCKS) - sound_nblocks = MAX_MEM_BLOCKS - 1; - - op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations))); - sound_nblocks++; - if (sound_nblocks >= MAX_MEM_BLOCKS) - sound_nblocks = MAX_MEM_BLOCKS - 1; - - if (d == NULL || op == NULL) { - printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name); - sound_unload_audiodev(num); - return -ENOMEM; - } - init_waitqueue_head(&op->in_sleeper); - init_waitqueue_head(&op->out_sleeper); - init_waitqueue_head(&op->poll_sleeper); - if (driver_size < sizeof(struct audio_driver)) - memset((char *) d, 0, sizeof(struct audio_driver)); - - memcpy((char *) d, (char *) driver, driver_size); - - op->d = d; - strlcpy(op->name, name, sizeof(op->name)); - op->flags = flags; - op->format_mask = format_mask; - op->devc = devc; - - /* - * Hardcoded defaults - */ - audio_devs[num] = op; - - DMAbuf_init(num, dma1, dma2); - - audio_init_devices(); - return num; -} -EXPORT_SYMBOL(sound_install_audiodrv); - -int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, - int driver_size, void *devc) -{ - struct mixer_operations *op; - - int n = sound_alloc_mixerdev(); - - if (n == -1) { - printk(KERN_ERR "Sound: Too many mixer drivers\n"); - return -EBUSY; - } - if (vers != MIXER_DRIVER_VERSION || - driver_size > sizeof(struct mixer_operations)) { - printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name); - return -EINVAL; - } - - /* FIXME: This leaks a mixer_operations struct every time its called - until you unload sound! */ - - op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations))); - sound_nblocks++; - if (sound_nblocks >= MAX_MEM_BLOCKS) - sound_nblocks = MAX_MEM_BLOCKS - 1; - - if (op == NULL) { - printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); - return -ENOMEM; - } - memcpy((char *) op, (char *) driver, driver_size); - - strlcpy(op->name, name, sizeof(op->name)); - op->devc = devc; - - mixer_devs[n] = op; - return n; -} -EXPORT_SYMBOL(sound_install_mixer); - -void sound_unload_audiodev(int dev) -{ - if (dev != -1) { - DMAbuf_deinit(dev); - audio_devs[dev] = NULL; - unregister_sound_dsp((dev<<4)+3); - } -} -EXPORT_SYMBOL(sound_unload_audiodev); - -static int sound_alloc_audiodev(void) -{ - int i = register_sound_dsp(&oss_sound_fops, -1); - if(i==-1) - return i; - i>>=4; - if(i>=num_audiodevs) - num_audiodevs = i + 1; - return i; -} - -int sound_alloc_mididev(void) -{ - int i = register_sound_midi(&oss_sound_fops, -1); - if(i==-1) - return i; - i>>=4; - if(i>=num_midis) - num_midis = i + 1; - return i; -} -EXPORT_SYMBOL(sound_alloc_mididev); - -int sound_alloc_synthdev(void) -{ - int i; - - for (i = 0; i < MAX_SYNTH_DEV; i++) { - if (synth_devs[i] == NULL) { - if (i >= num_synths) - num_synths++; - return i; - } - } - return -1; -} -EXPORT_SYMBOL(sound_alloc_synthdev); - -int sound_alloc_mixerdev(void) -{ - int i = register_sound_mixer(&oss_sound_fops, -1); - if(i==-1) - return -1; - i>>=4; - if(i>=num_mixers) - num_mixers = i + 1; - return i; -} -EXPORT_SYMBOL(sound_alloc_mixerdev); - -int sound_alloc_timerdev(void) -{ - int i; - - for (i = 0; i < MAX_TIMER_DEV; i++) { - if (sound_timer_devs[i] == NULL) { - if (i >= num_sound_timers) - num_sound_timers++; - return i; - } - } - return -1; -} -EXPORT_SYMBOL(sound_alloc_timerdev); - -void sound_unload_mixerdev(int dev) -{ - if (dev != -1) { - mixer_devs[dev] = NULL; - unregister_sound_mixer(dev<<4); - num_mixers--; - } -} -EXPORT_SYMBOL(sound_unload_mixerdev); - -void sound_unload_mididev(int dev) -{ - if (dev != -1) { - midi_devs[dev] = NULL; - unregister_sound_midi((dev<<4)+2); - } -} -EXPORT_SYMBOL(sound_unload_mididev); - -void sound_unload_synthdev(int dev) -{ - if (dev != -1) - synth_devs[dev] = NULL; -} -EXPORT_SYMBOL(sound_unload_synthdev); - -void sound_unload_timerdev(int dev) -{ - if (dev != -1) - sound_timer_devs[dev] = NULL; -} -EXPORT_SYMBOL(sound_unload_timerdev); - diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h deleted file mode 100644 index 0199a317c5a9..000000000000 --- a/sound/oss/dev_table.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - * dev_table.h - * - * Global definitions for device call tables - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - - -#ifndef _DEV_TABLE_H_ -#define _DEV_TABLE_H_ - -#include <linux/spinlock.h> -/* - * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) - * Numbers 1000 to N are reserved for driver's internal use. - */ - -#define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ -#define SNDCARD_VIDC 28 /* ARMs VIDC */ -#define SNDCARD_SBPNP 29 -#define SNDCARD_SOFTOSS 36 -#define SNDCARD_VMIDI 37 -#define SNDCARD_OPL3SA1 38 /* Note: clash in msnd.h */ -#define SNDCARD_OPL3SA1_SB 39 -#define SNDCARD_OPL3SA1_MPU 40 -#define SNDCARD_WAVEFRONT 41 -#define SNDCARD_OPL3SA2 42 -#define SNDCARD_OPL3SA2_MPU 43 -#define SNDCARD_WAVEARTIST 44 /* Waveartist */ -#define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ -#define SNDCARD_AD1816 88 - -/* - * NOTE! NOTE! NOTE! NOTE! - * - * If you modify this file, please check the dev_table.c also. - * - * NOTE! NOTE! NOTE! NOTE! - */ - -struct driver_info -{ - char *driver_id; - int card_subtype; /* Driver specific. Usually 0 */ - int card_type; /* From soundcard.h */ - char *name; - void (*attach) (struct address_info *hw_config); - int (*probe) (struct address_info *hw_config); - void (*unload) (struct address_info *hw_config); -}; - -struct card_info -{ - int card_type; /* Link (search key) to the driver list */ - struct address_info config; - int enabled; - void *for_driver_use; -}; - - -/* - * Device specific parameters (used only by dmabuf.c) - */ -#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR) - -#define DMODE_NONE 0 -#define DMODE_OUTPUT PCM_ENABLE_OUTPUT -#define DMODE_INPUT PCM_ENABLE_INPUT - -struct dma_buffparms -{ - int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ - int closing; - - /* - * Pointers to raw buffers - */ - - char *raw_buf; - unsigned long raw_buf_phys; - int buffsize; - - /* - * Device state tables - */ - - unsigned long flags; -#define DMA_BUSY 0x00000001 -#define DMA_RESTART 0x00000002 -#define DMA_ACTIVE 0x00000004 -#define DMA_STARTED 0x00000008 -#define DMA_EMPTY 0x00000010 -#define DMA_ALLOC_DONE 0x00000020 -#define DMA_SYNCING 0x00000040 -#define DMA_DIRTY 0x00000080 -#define DMA_POST 0x00000100 -#define DMA_NODMA 0x00000200 -#define DMA_NOTIMEOUT 0x00000400 - - int open_mode; - - /* - * Queue parameters. - */ - int qlen; - int qhead; - int qtail; - spinlock_t lock; - - int cfrag; /* Current incomplete fragment (write) */ - - int nbufs; - int counts[MAX_SUB_BUFFERS]; - int subdivision; - - int fragment_size; - int needs_reorg; - int max_fragments; - - int bytes_in_use; - - int underrun_count; - unsigned long byte_counter; - unsigned long user_counter; - unsigned long max_byte_counter; - int data_rate; /* Bytes/second */ - - int mapping_flags; -#define DMA_MAP_MAPPED 0x00000001 - char neutral_byte; - int dma; /* DMA channel */ - - int applic_profile; /* Application profile (APF_*) */ - /* Interrupt callback stuff */ - void (*audio_callback) (int dev, int parm); - int callback_parm; - - int buf_flags[MAX_SUB_BUFFERS]; -#define BUFF_EOF 0x00000001 /* Increment eof count */ -#define BUFF_DIRTY 0x00000002 /* Buffer written */ -}; - -/* - * Structure for use with various microcontrollers and DSP processors - * in the recent sound cards. - */ -typedef struct coproc_operations -{ - char name[64]; - struct module *owner; - int (*open) (void *devc, int sub_device); - void (*close) (void *devc, int sub_device); - int (*ioctl) (void *devc, unsigned int cmd, void __user * arg, int local); - void (*reset) (void *devc); - - void *devc; /* Driver specific info */ -} coproc_operations; - -struct audio_driver -{ - struct module *owner; - int (*open) (int dev, int mode); - void (*close) (int dev); - void (*output_block) (int dev, unsigned long buf, - int count, int intrflag); - void (*start_input) (int dev, unsigned long buf, - int count, int intrflag); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - int (*prepare_for_input) (int dev, int bufsize, int nbufs); - int (*prepare_for_output) (int dev, int bufsize, int nbufs); - void (*halt_io) (int dev); - int (*local_qlen)(int dev); - void (*copy_user) (int dev, - char *localbuf, int localoffs, - const char __user *userbuf, int useroffs, - int max_in, int max_out, - int *used, int *returned, - int len); - void (*halt_input) (int dev); - void (*halt_output) (int dev); - void (*trigger) (int dev, int bits); - int (*set_speed)(int dev, int speed); - unsigned int (*set_bits)(int dev, unsigned int bits); - short (*set_channels)(int dev, short channels); - void (*postprocess_write)(int dev); /* Device spesific postprocessing for written data */ - void (*preprocess_read)(int dev); /* Device spesific preprocessing for read data */ - void (*mmap)(int dev); -}; - -struct audio_operations -{ - char name[128]; - int flags; -#define NOTHING_SPECIAL 0x00 -#define NEEDS_RESTART 0x01 -#define DMA_AUTOMODE 0x02 -#define DMA_DUPLEX 0x04 -#define DMA_PSEUDO_AUTOMODE 0x08 -#define DMA_HARDSTOP 0x10 -#define DMA_EXACT 0x40 -#define DMA_NORESET 0x80 - int format_mask; /* Bitmask for supported audio formats */ - void *devc; /* Driver specific info */ - struct audio_driver *d; - void *portc; /* Driver specific info */ - struct dma_buffparms *dmap_in, *dmap_out; - struct coproc_operations *coproc; - int mixer_dev; - int enable_bits; - int open_mode; - int go; - int min_fragment; /* 0 == unlimited */ - int max_fragment; /* 0 == unlimited */ - int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ - - /* fields formerly in dmabuf.c */ - wait_queue_head_t in_sleeper; - wait_queue_head_t out_sleeper; - wait_queue_head_t poll_sleeper; - - /* fields formerly in audio.c */ - int audio_mode; - -#define AM_NONE 0 -#define AM_WRITE OPEN_WRITE -#define AM_READ OPEN_READ - - int local_format; - int audio_format; - int local_conversion; -#define CNV_MU_LAW 0x00000001 - - /* large structures at the end to keep offsets small */ - struct dma_buffparms dmaps[2]; -}; - -int *load_mixer_volumes(char *name, int *levels, int present); - -struct mixer_operations -{ - struct module *owner; - char id[16]; - char name[64]; - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - - void *devc; - int modify_counter; -}; - -struct synth_operations -{ - struct module *owner; - char *id; /* Unique identifier (ASCII) max 29 char */ - struct synth_info *info; - int midi_dev; - int synth_type; - int synth_subtype; - - int (*open) (int dev, int mode); - void (*close) (int dev); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - int (*kill_note) (int dev, int voice, int note, int velocity); - int (*start_note) (int dev, int voice, int note, int velocity); - int (*set_instr) (int dev, int voice, int instr); - void (*reset) (int dev); - void (*hw_control) (int dev, unsigned char *event); - int (*load_patch) (int dev, int format, const char __user *addr, - int count, int pmgr_flag); - void (*aftertouch) (int dev, int voice, int pressure); - void (*controller) (int dev, int voice, int ctrl_num, int value); - void (*panning) (int dev, int voice, int value); - void (*volume_method) (int dev, int mode); - void (*bender) (int dev, int chn, int value); - int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc); - void (*setup_voice) (int dev, int voice, int chn); - int (*send_sysex)(int dev, unsigned char *bytes, int len); - - struct voice_alloc_info alloc; - struct channel_info chn_info[16]; - int emulation; -#define EMU_GM 1 /* General MIDI */ -#define EMU_XG 2 /* Yamaha XG */ -#define MAX_SYSEX_BUF 64 - unsigned char sysex_buf[MAX_SYSEX_BUF]; - int sysex_ptr; -}; - -struct midi_input_info -{ - /* MIDI input scanner variables */ -#define MI_MAX 10 - volatile int m_busy; - unsigned char m_buf[MI_MAX]; - unsigned char m_prev_status; /* For running status */ - int m_ptr; -#define MST_INIT 0 -#define MST_DATA 1 -#define MST_SYSEX 2 - int m_state; - int m_left; -}; - -struct midi_operations -{ - struct module *owner; - struct midi_info info; - struct synth_operations *converter; - struct midi_input_info in_info; - int (*open) (int dev, int mode, - void (*inputintr)(int dev, unsigned char data), - void (*outputintr)(int dev) - ); - void (*close) (int dev); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - int (*outputc) (int dev, unsigned char data); - int (*start_read) (int dev); - int (*end_read) (int dev); - void (*kick)(int dev); - int (*command) (int dev, unsigned char *data); - int (*buffer_status) (int dev); - int (*prefix_cmd) (int dev, unsigned char status); - struct coproc_operations *coproc; - void *devc; -}; - -struct sound_lowlev_timer -{ - int dev; - int priority; - unsigned int (*tmr_start)(int dev, unsigned int usecs); - void (*tmr_disable)(int dev); - void (*tmr_restart)(int dev); -}; - -struct sound_timer_operations -{ - struct module *owner; - struct sound_timer_info info; - int priority; - int devlink; - int (*open)(int dev, int mode); - void (*close)(int dev); - int (*event)(int dev, unsigned char *ev); - unsigned long (*get_time)(int dev); - int (*ioctl) (int dev, unsigned int cmd, void __user * arg); - void (*arm_timer)(int dev, long time); -}; - -extern struct sound_timer_operations default_sound_timer; - -extern struct audio_operations *audio_devs[MAX_AUDIO_DEV]; -extern int num_audiodevs; -extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; -extern int num_mixers; -extern struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; -extern int num_synths; -extern struct midi_operations *midi_devs[MAX_MIDI_DEV]; -extern int num_midis; -extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; -extern int num_sound_timers; - -extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); -void sound_timer_init (struct sound_lowlev_timer *t, char *name); -void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan); - -#define AUDIO_DRIVER_VERSION 2 -#define MIXER_DRIVER_VERSION 2 -int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, - int driver_size, int flags, unsigned int format_mask, - void *devc, int dma1, int dma2); -int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, - int driver_size, void *devc); - -void sound_unload_audiodev(int dev); -void sound_unload_mixerdev(int dev); -void sound_unload_mididev(int dev); -void sound_unload_synthdev(int dev); -void sound_unload_timerdev(int dev); -int sound_alloc_mixerdev(void); -int sound_alloc_timerdev(void); -int sound_alloc_synthdev(void); -int sound_alloc_mididev(void); -#endif /* _DEV_TABLE_H_ */ - diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c deleted file mode 100644 index c5dd396c66a2..000000000000 --- a/sound/oss/dmabuf.c +++ /dev/null @@ -1,1268 +0,0 @@ -/* - * sound/oss/dmabuf.c - * - * The DMA buffer manager for digitized voice applications - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Thomas Sailer : moved several static variables into struct audio_operations - * (which is grossly misnamed btw.) because they have the same - * lifetime as the rest in there and dynamic allocation saves - * 12k or so - * Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to - * determine if it was woken up by the expiring timeout or by - * an explicit wake_up. The return value from schedule_timeout - * can be used instead; if 0, the wakeup was due to the timeout. - * - * Rob Riggs Added persistent DMA buffers (1998/10/17) - */ - -#define BE_CONSERVATIVE -#define SAMPLE_ROUNDUP 0 - -#include <linux/mm.h> -#include <linux/gfp.h> -#include <linux/sched/signal.h> - -#include "sound_config.h" -#include "sleep.h" - -#define DMAP_FREE_ON_CLOSE 0 -#define DMAP_KEEP_ON_CLOSE 1 -extern int sound_dmap_flag; - -static void dma_reset_output(int dev); -static void dma_reset_input(int dev); -static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode); - - - -static int debugmem; /* switched off by default */ -static int dma_buffsize = DSP_BUFFSIZE; - -static long dmabuf_timeout(struct dma_buffparms *dmap) -{ - long tmout; - - tmout = (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 5; /* Some safety distance */ - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - return tmout; -} - -static int sound_alloc_dmap(struct dma_buffparms *dmap) -{ - char *start_addr, *end_addr; - int dma_pagesize; - int sz, size; - struct page *page; - - dmap->mapping_flags &= ~DMA_MAP_MAPPED; - - if (dmap->raw_buf != NULL) - return 0; /* Already done */ - if (dma_buffsize < 4096) - dma_buffsize = 4096; - dma_pagesize = (dmap->dma < 4) ? (64 * 1024) : (128 * 1024); - - /* - * Now check for the Cyrix problem. - */ - - if(isa_dma_bridge_buggy==2) - dma_pagesize=32768; - - dmap->raw_buf = NULL; - dmap->buffsize = dma_buffsize; - if (dmap->buffsize > dma_pagesize) - dmap->buffsize = dma_pagesize; - start_addr = NULL; - /* - * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. Don't accept smaller than 8k buffer for performance - * reasons. - */ - while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) { - for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); - dmap->buffsize = PAGE_SIZE * (1 << sz); - start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA|__GFP_NOWARN, sz); - if (start_addr == NULL) - dmap->buffsize /= 2; - } - - if (start_addr == NULL) { - printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n"); - return -ENOMEM; - } else { - /* make some checks */ - end_addr = start_addr + dmap->buffsize - 1; - - if (debugmem) - printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); - - /* now check if it fits into the same dma-pagesize */ - - if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) { - printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); - return -EFAULT; - } - } - dmap->raw_buf = start_addr; - dmap->raw_buf_phys = dma_map_single(NULL, start_addr, dmap->buffsize, DMA_BIDIRECTIONAL); - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - SetPageReserved(page); - return 0; -} - -static void sound_free_dmap(struct dma_buffparms *dmap) -{ - int sz, size; - struct page *page; - unsigned long start_addr, end_addr; - - if (dmap->raw_buf == NULL) - return; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return; /* Don't free mmapped buffer. Will use it next time */ - for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); - - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + dmap->buffsize; - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - ClearPageReserved(page); - - dma_unmap_single(NULL, dmap->raw_buf_phys, dmap->buffsize, DMA_BIDIRECTIONAL); - free_pages((unsigned long) dmap->raw_buf, sz); - dmap->raw_buf = NULL; -} - - -/* Intel version !!!!!!!!! */ - -static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, int count, int dma_mode) -{ - unsigned long flags; - int chan = dmap->dma; - - /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - - flags = claim_dma_lock(); - disable_dma(chan); - clear_dma_ff(chan); - set_dma_mode(chan, dma_mode); - set_dma_addr(chan, physaddr); - set_dma_count(chan, count); - enable_dma(chan); - release_dma_lock(flags); - - return 0; -} - -static void dma_init_buffers(struct dma_buffparms *dmap) -{ - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->bytes_in_use = dmap->buffsize; - - dmap->dma_mode = DMODE_NONE; - dmap->mapping_flags = 0; - dmap->neutral_byte = 0x80; - dmap->data_rate = 8000; - dmap->cfrag = -1; - dmap->closing = 0; - dmap->nbufs = 1; - dmap->flags = DMA_BUSY; /* Other flags off */ -} - -static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffparms *dmap) -{ - int err; - - if (dmap->flags & DMA_BUSY) - return -EBUSY; - if ((err = sound_alloc_dmap(dmap)) < 0) - return err; - - if (dmap->raw_buf == NULL) { - printk(KERN_WARNING "Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - if (dmap->dma >= 0 && sound_open_dma(dmap->dma, adev->name)) { - printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma); - return -EBUSY; - } - dma_init_buffers(dmap); - spin_lock_init(&dmap->lock); - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->applic_profile = APF_NORMAL; - dmap->needs_reorg = 1; - dmap->audio_callback = NULL; - dmap->callback_parm = 0; - return 0; -} - -static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap) -{ - unsigned long flags; - - if (dmap->dma >= 0) { - sound_close_dma(dmap->dma); - flags=claim_dma_lock(); - disable_dma(dmap->dma); - release_dma_lock(flags); - } - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; - - if (sound_dmap_flag == DMAP_FREE_ON_CLOSE) - sound_free_dmap(dmap); -} - - -static unsigned int default_set_bits(int dev, unsigned int bits) -{ - mm_segment_t fs = get_fs(); - - set_fs(get_ds()); - audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (void __user *)&bits); - set_fs(fs); - return bits; -} - -static int default_set_speed(int dev, int speed) -{ - mm_segment_t fs = get_fs(); - - set_fs(get_ds()); - audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (void __user *)&speed); - set_fs(fs); - return speed; -} - -static short default_set_channels(int dev, short channels) -{ - int c = channels; - mm_segment_t fs = get_fs(); - - set_fs(get_ds()); - audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (void __user *)&c); - set_fs(fs); - return c; -} - -static void check_driver(struct audio_driver *d) -{ - if (d->set_speed == NULL) - d->set_speed = default_set_speed; - if (d->set_bits == NULL) - d->set_bits = default_set_bits; - if (d->set_channels == NULL) - d->set_channels = default_set_channels; -} - -int DMAbuf_open(int dev, int mode) -{ - struct audio_operations *adev = audio_devs[dev]; - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (!adev) - return -ENXIO; - if (!(adev->flags & DMA_DUPLEX)) - adev->dmap_in = adev->dmap_out; - check_driver(adev->d); - - if ((retval = adev->d->open(dev, mode)) < 0) - return retval; - dmap_out = adev->dmap_out; - dmap_in = adev->dmap_in; - if (dmap_in == dmap_out) - adev->flags &= ~DMA_DUPLEX; - - if (mode & OPEN_WRITE) { - if ((retval = open_dmap(adev, mode, dmap_out)) < 0) { - adev->d->close(dev); - return retval; - } - } - adev->enable_bits = mode; - - if (mode == OPEN_READ || (mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) { - if ((retval = open_dmap(adev, mode, dmap_in)) < 0) { - adev->d->close(dev); - if (mode & OPEN_WRITE) - close_dmap(adev, dmap_out); - return retval; - } - } - adev->open_mode = mode; - adev->go = 1; - - adev->d->set_bits(dev, 8); - adev->d->set_channels(dev, 1); - adev->d->set_speed(dev, DSP_DEFAULT_SPEED); - if (adev->dmap_out->dma_mode == DMODE_OUTPUT) - memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, - adev->dmap_out->bytes_in_use); - return 0; -} -/* MUST not hold the spinlock */ -void DMAbuf_reset(int dev) -{ - if (audio_devs[dev]->open_mode & OPEN_WRITE) - dma_reset_output(dev); - - if (audio_devs[dev]->open_mode & OPEN_READ) - dma_reset_input(dev); -} - -static void dma_reset_output(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags,f ; - struct dma_buffparms *dmap = adev->dmap_out; - - if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ - return; - - /* - * First wait until the current fragment has been played completely - */ - spin_lock_irqsave(&dmap->lock,flags); - adev->dmap_out->flags |= DMA_SYNCING; - - adev->dmap_out->underrun_count = 0; - if (!signal_pending(current) && adev->dmap_out->qlen && - adev->dmap_out->underrun_count == 0){ - spin_unlock_irqrestore(&dmap->lock,flags); - oss_broken_sleep_on(&adev->out_sleeper, dmabuf_timeout(dmap)); - spin_lock_irqsave(&dmap->lock,flags); - } - adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - - /* - * Finally shut the device off - */ - if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_output) - adev->d->halt_io(dev); - else - adev->d->halt_output(dev); - adev->dmap_out->flags &= ~DMA_STARTED; - - f=claim_dma_lock(); - clear_dma_ff(dmap->dma); - disable_dma(dmap->dma); - release_dma_lock(f); - - dmap->byte_counter = 0; - reorganize_buffers(dev, adev->dmap_out, 0); - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - spin_unlock_irqrestore(&dmap->lock,flags); -} - -static void dma_reset_input(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - struct dma_buffparms *dmap = adev->dmap_in; - - spin_lock_irqsave(&dmap->lock,flags); - if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input) - adev->d->halt_io(dev); - else - adev->d->halt_input(dev); - adev->dmap_in->flags &= ~DMA_STARTED; - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - reorganize_buffers(dev, adev->dmap_in, 1); - spin_unlock_irqrestore(&dmap->lock,flags); -} -/* MUST be called with holding the dmap->lock */ -void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) -{ - struct audio_operations *adev = audio_devs[dev]; - - if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ - dmap->dma_mode = DMODE_OUTPUT; - - if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { - if (!(dmap->flags & DMA_STARTED)) { - reorganize_buffers(dev, dmap, 0); - if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs)) - return; - if (!(dmap->flags & DMA_NODMA)) - local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE); - dmap->flags |= DMA_STARTED; - } - if (dmap->counts[dmap->qhead] == 0) - dmap->counts[dmap->qhead] = dmap->fragment_size; - dmap->dma_mode = DMODE_OUTPUT; - adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (adev->d->trigger) - adev->d->trigger(dev,adev->enable_bits * adev->go); - } - dmap->flags |= DMA_ACTIVE; -} - -int DMAbuf_sync(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - int n = 0; - struct dma_buffparms *dmap; - - if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { - dmap = adev->dmap_out; - spin_lock_irqsave(&dmap->lock,flags); - if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output(dev, dmap); - adev->dmap_out->flags |= DMA_SYNCING; - adev->dmap_out->underrun_count = 0; - while (!signal_pending(current) && n++ < adev->dmap_out->nbufs && - adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { - long t = dmabuf_timeout(dmap); - spin_unlock_irqrestore(&dmap->lock,flags); - /* FIXME: not safe may miss events */ - t = oss_broken_sleep_on(&adev->out_sleeper, t); - spin_lock_irqsave(&dmap->lock,flags); - if (!t) { - adev->dmap_out->flags &= ~DMA_SYNCING; - spin_unlock_irqrestore(&dmap->lock,flags); - return adev->dmap_out->qlen; - } - } - adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - - /* - * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait until the device has finished playing. - */ - - /* still holding the lock */ - if (adev->d->local_qlen) { /* Device has hidden buffers */ - while (!signal_pending(current) && - adev->d->local_qlen(dev)){ - spin_unlock_irqrestore(&dmap->lock,flags); - oss_broken_sleep_on(&adev->out_sleeper, - dmabuf_timeout(dmap)); - spin_lock_irqsave(&dmap->lock,flags); - } - } - spin_unlock_irqrestore(&dmap->lock,flags); - } - adev->dmap_out->dma_mode = DMODE_NONE; - return adev->dmap_out->qlen; -} - -int DMAbuf_release(int dev, int mode) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap; - unsigned long flags; - - dmap = adev->dmap_out; - if (adev->open_mode & OPEN_WRITE) - adev->dmap_out->closing = 1; - - if (adev->open_mode & OPEN_READ){ - adev->dmap_in->closing = 1; - dmap = adev->dmap_in; - } - if (adev->open_mode & OPEN_WRITE) - if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)) - if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) - DMAbuf_sync(dev); - if (adev->dmap_out->dma_mode == DMODE_OUTPUT) - memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use); - - DMAbuf_reset(dev); - spin_lock_irqsave(&dmap->lock,flags); - adev->d->close(dev); - - if (adev->open_mode & OPEN_WRITE) - close_dmap(adev, adev->dmap_out); - - if (adev->open_mode == OPEN_READ || - (adev->open_mode != OPEN_WRITE && - (adev->flags & DMA_DUPLEX))) - close_dmap(adev, adev->dmap_in); - adev->open_mode = 0; - spin_unlock_irqrestore(&dmap->lock,flags); - return 0; -} -/* called with dmap->lock dold */ -int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) -{ - struct audio_operations *adev = audio_devs[dev]; - int err; - - if (!(adev->open_mode & OPEN_READ)) - return 0; - if (!(adev->enable_bits & PCM_ENABLE_INPUT)) - return 0; - if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ - /* release lock - it's not recursive */ - spin_unlock_irq(&dmap->lock); - DMAbuf_sync(dev); - DMAbuf_reset(dev); - spin_lock_irq(&dmap->lock); - dmap->dma_mode = DMODE_NONE; - } - if (!dmap->dma_mode) { - reorganize_buffers(dev, dmap, 1); - if ((err = adev->d->prepare_for_input(dev, - dmap->fragment_size, dmap->nbufs)) < 0) - return err; - dmap->dma_mode = DMODE_INPUT; - } - if (!(dmap->flags & DMA_ACTIVE)) { - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); - adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (adev->d->trigger) - adev->d->trigger(dev, adev->enable_bits * adev->go); - } - return 0; -} -/* acquires lock */ -int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = adev->dmap_in; - - if (!(adev->open_mode & OPEN_READ)) - return -EIO; - spin_lock_irqsave(&dmap->lock,flags); - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) { -/* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ - spin_unlock_irqrestore(&dmap->lock,flags); - return -EINVAL; - } else while (dmap->qlen <= 0 && n++ < 10) { - long timeout = MAX_SCHEDULE_TIMEOUT; - if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { - spin_unlock_irqrestore(&dmap->lock,flags); - return -EAGAIN; - } - if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { - spin_unlock_irqrestore(&dmap->lock,flags); - return err; - } - /* Wait for the next block */ - - if (dontblock) { - spin_unlock_irqrestore(&dmap->lock,flags); - return -EAGAIN; - } - if (adev->go) - timeout = dmabuf_timeout(dmap); - - spin_unlock_irqrestore(&dmap->lock,flags); - timeout = oss_broken_sleep_on(&adev->in_sleeper, timeout); - if (!timeout) { - /* FIXME: include device name */ - err = -EIO; - printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input(dev); - } else - err = -EINTR; - spin_lock_irqsave(&dmap->lock,flags); - } - spin_unlock_irqrestore(&dmap->lock,flags); - - if (dmap->qlen <= 0) - return err ? err : -EINTR; - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; -} - -int DMAbuf_rmchars(int dev, int buff_no, int c) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - int p = dmap->counts[dmap->qhead] + c; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { -/* printk("Sound: Can't read from mmapped device (2)\n");*/ - return -EINVAL; - } - else if (dmap->qlen <= 0) - return -EIO; - else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } - else dmap->counts[dmap->qhead] = p; - - return 0; -} -/* MUST be called with dmap->lock hold */ -int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction) -{ - /* - * Try to approximate the active byte position of the DMA pointer within the - * buffer area as well as possible. - */ - - int pos; - unsigned long f; - - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else { - int chan = dmap->dma; - - f=claim_dma_lock(); - clear_dma_ff(chan); - - if(!isa_dma_bridge_buggy) - disable_dma(dmap->dma); - - pos = get_dma_residue(chan); - - pos = dmap->bytes_in_use - pos; - - if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) { - if (direction == DMODE_OUTPUT) { - if (dmap->qhead == 0) - if (pos > dmap->fragment_size) - pos = 0; - } else { - if (dmap->qtail == 0) - if (pos > dmap->fragment_size) - pos = 0; - } - } - if (pos < 0) - pos = 0; - if (pos >= dmap->bytes_in_use) - pos = 0; - - if(!isa_dma_bridge_buggy) - enable_dma(dmap->dma); - - release_dma_lock(f); - } - /* printk( "%04x ", pos); */ - - return pos; -} - -/* - * DMAbuf_start_devices() is called by the /dev/music driver to start - * one or more audio devices at desired moment. - */ - -void DMAbuf_start_devices(unsigned int devmask) -{ - struct audio_operations *adev; - int dev; - - for (dev = 0; dev < num_audiodevs; dev++) { - if (!(devmask & (1 << dev))) - continue; - if (!(adev = audio_devs[dev])) - continue; - if (adev->open_mode == 0) - continue; - if (adev->go) - continue; - /* OK to start the device */ - adev->go = 1; - if (adev->d->trigger) - adev->d->trigger(dev,adev->enable_bits * adev->go); - } -} -/* via poll called without a lock ?*/ -int DMAbuf_space_in_queue(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - int len, max, tmp; - struct dma_buffparms *dmap = adev->dmap_out; - int lim = dmap->nbufs; - - if (lim < 2) - lim = 2; - - if (dmap->qlen >= lim) /* No space at all */ - return 0; - - /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ - - max = dmap->max_fragments; - if (max > lim) - max = lim; - len = dmap->qlen; - - if (adev->d->local_qlen) { - tmp = adev->d->local_qlen(dev); - if (tmp && len) - tmp--; /* This buffer has been counted twice */ - len += tmp; - } - if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ - len = len + 1; - - if (len >= max) - return 0; - return max - len; -} -/* MUST not hold the spinlock - this function may sleep */ -static int output_sleep(int dev, int dontblock) -{ - struct audio_operations *adev = audio_devs[dev]; - int err = 0; - struct dma_buffparms *dmap = adev->dmap_out; - long timeout; - long timeout_value; - - if (dontblock) - return -EAGAIN; - if (!(adev->enable_bits & PCM_ENABLE_OUTPUT)) - return -EAGAIN; - - /* - * Wait for free space - */ - if (signal_pending(current)) - return -EINTR; - timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); - if (timeout) - timeout_value = dmabuf_timeout(dmap); - else - timeout_value = MAX_SCHEDULE_TIMEOUT; - timeout_value = oss_broken_sleep_on(&adev->out_sleeper, timeout_value); - if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) { - printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - dma_reset_output(dev); - } else { - if (signal_pending(current)) - err = -EINTR; - } - return err; -} -/* called with the lock held */ -static int find_output_space(int dev, char **buf, int *size) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - unsigned long active_offs; - long len, offs; - int maxfrags; - int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - - *buf = dmap->raw_buf; - if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) - return 0; - -#ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; -#else - active_offs = max(DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT), 0); - /* Check for pointer wrapping situation */ - if (active_offs >= dmap->bytes_in_use) - active_offs = 0; - active_offs += dmap->byte_counter; -#endif - - offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP; - if (offs < 0 || offs >= dmap->bytes_in_use) { - printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs); - printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); - return 0; - } - *buf = dmap->raw_buf + offs; - - len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - - if ((offs + len) > dmap->bytes_in_use) - len = dmap->bytes_in_use - offs; - if (len < 0) { - return 0; - } - if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) - len = (maxfrags * dmap->fragment_size) - occupied_bytes; - *size = len & ~SAMPLE_ROUNDUP; - return (*size > 0); -} -/* acquires lock */ -int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = adev->dmap_out; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) { -/* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ - return -EINVAL; - } - spin_lock_irqsave(&dmap->lock,flags); - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - - if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ - spin_unlock_irqrestore(&dmap->lock,flags); - DMAbuf_reset(dev); - spin_lock_irqsave(&dmap->lock,flags); - } - dmap->dma_mode = DMODE_OUTPUT; - - while (find_output_space(dev, buf, size) <= 0) { - spin_unlock_irqrestore(&dmap->lock,flags); - if ((err = output_sleep(dev, dontblock)) < 0) { - return err; - } - spin_lock_irqsave(&dmap->lock,flags); - } - - spin_unlock_irqrestore(&dmap->lock,flags); - return 0; -} -/* has to acquire dmap->lock */ -int DMAbuf_move_wrpointer(int dev, int l) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - unsigned long ptr; - unsigned long end_ptr, p; - int post; - unsigned long flags; - - spin_lock_irqsave(&dmap->lock,flags); - post= (dmap->flags & DMA_POST); - ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - - dmap->flags &= ~DMA_POST; - dmap->cfrag = -1; - dmap->user_counter += l; - dmap->flags |= DMA_DIRTY; - - if (dmap->byte_counter >= dmap->max_byte_counter) { - /* Wrap the byte counters */ - long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - - p = (dmap->user_counter - 1) % dmap->bytes_in_use; - dmap->neutral_byte = dmap->raw_buf[p]; - - /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) { - dmap->counts[dmap->qtail] = dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - ptr += dmap->fragment_size; - } - - dmap->counts[dmap->qtail] = dmap->user_counter - ptr; - - /* - * Let the low level driver perform some postprocessing to - * the written data. - */ - if (adev->d->postprocess_write) - adev->d->postprocess_write(dev); - - if (!(dmap->flags & DMA_ACTIVE)) - if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - DMAbuf_launch_output(dev, dmap); - - spin_unlock_irqrestore(&dmap->lock,flags); - return 0; -} - -int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "sound: DMA buffer(1) == NULL\n"); - printk("Device %d, chn=%s\n", dev, (dmap == adev->dmap_out) ? "out" : "in"); - return 0; - } - if (dmap->dma < 0) - return 0; - sound_start_dma(dmap, physaddr, count, dma_mode); - return count; -} -EXPORT_SYMBOL(DMAbuf_start_dma); - -static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode) -{ - struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "sound: DMA buffer(2) == NULL\n"); - printk(KERN_ERR "Device %s, chn=%s\n", adev->name, (dmap == adev->dmap_out) ? "out" : "in"); - return 0; - } - if (dmap->flags & DMA_NODMA) - return 1; - if (dmap->dma < 0) - return 0; - sound_start_dma(dmap, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode | DMA_AUTOINIT); - dmap->flags |= DMA_STARTED; - return count; -} - -static void finish_output_interrupt(int dev, struct dma_buffparms *dmap) -{ - struct audio_operations *adev = audio_devs[dev]; - - if (dmap->audio_callback != NULL) - dmap->audio_callback(dev, dmap->callback_parm); - wake_up(&adev->out_sleeper); - wake_up(&adev->poll_sleeper); -} -/* called with dmap->lock held in irq context*/ -static void do_outputintr(int dev, int dummy) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - int this_fragment; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "Sound: Error. Audio interrupt (%d) after freeing buffers.\n", dev); - return; - } - if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* Virtual memory mapped access */ - /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) { /* Wrapped */ - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ - long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(adev->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - DMAbuf_launch_output(dev, dmap); - finish_output_interrupt(dev, dmap); - return; - } - - dmap->qlen--; - this_fragment = dmap->qhead; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - - if (dmap->qhead == 0) { /* Wrapped */ - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ - long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - if (!(adev->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - - /* - * This is dmap->qlen <= 0 except when closing when - * dmap->qlen < 0 - */ - - while (dmap->qlen <= -dmap->closing) { - dmap->underrun_count++; - dmap->qlen++; - if ((dmap->flags & DMA_DIRTY) && dmap->applic_profile != APF_CPUINTENS) { - dmap->flags &= ~DMA_DIRTY; - memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, - adev->dmap_out->buffsize); - } - dmap->user_counter += dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - if (dmap->qlen > 0) - DMAbuf_launch_output(dev, dmap); - finish_output_interrupt(dev, dmap); -} -/* called in irq context */ -void DMAbuf_outputintr(int dev, int notify_only) -{ - struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; - struct dma_buffparms *dmap = adev->dmap_out; - - spin_lock_irqsave(&dmap->lock,flags); - if (!(dmap->flags & DMA_NODMA)) { - int chan = dmap->dma, pos, n; - unsigned long f; - - f=claim_dma_lock(); - - if(!isa_dma_bridge_buggy) - disable_dma(dmap->dma); - clear_dma_ff(chan); - pos = dmap->bytes_in_use - get_dma_residue(chan); - if(!isa_dma_bridge_buggy) - enable_dma(dmap->dma); - release_dma_lock(f); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - n = 0; - while (dmap->qhead != pos && n++ < dmap->nbufs) - do_outputintr(dev, notify_only); - } - else - do_outputintr(dev, notify_only); - spin_unlock_irqrestore(&dmap->lock,flags); -} -EXPORT_SYMBOL(DMAbuf_outputintr); - -/* called with dmap->lock held in irq context */ -static void do_inputintr(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "Sound: Fatal error. Audio interrupt after freeing buffers.\n"); - return; - } - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) { /* Wrapped */ - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ - long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; - - if (!(adev->flags & DMA_AUTOMODE)) { - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_READ); - adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (adev->d->trigger) - adev->d->trigger(dev, adev->enable_bits * adev->go); - } - dmap->flags |= DMA_ACTIVE; - } else if (dmap->qlen >= (dmap->nbufs - 1)) { - printk(KERN_WARNING "Sound: Recording overrun\n"); - dmap->underrun_count++; - - /* Just throw away the oldest fragment but keep the engine running */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) { - dmap->qlen++; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) { /* Wrapped */ - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ - long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - } - if (!(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { - local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); - adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1); - if (adev->d->trigger) - adev->d->trigger(dev,adev->enable_bits * adev->go); - } - dmap->flags |= DMA_ACTIVE; - if (dmap->qlen > 0) - { - wake_up(&adev->in_sleeper); - wake_up(&adev->poll_sleeper); - } -} -/* called in irq context */ -void DMAbuf_inputintr(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - unsigned long flags; - - spin_lock_irqsave(&dmap->lock,flags); - - if (!(dmap->flags & DMA_NODMA)) { - int chan = dmap->dma, pos, n; - unsigned long f; - - f=claim_dma_lock(); - if(!isa_dma_bridge_buggy) - disable_dma(dmap->dma); - clear_dma_ff(chan); - pos = dmap->bytes_in_use - get_dma_residue(chan); - if(!isa_dma_bridge_buggy) - enable_dma(dmap->dma); - release_dma_lock(f); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qtail != pos && ++n < dmap->nbufs) - do_inputintr(dev); - } else - do_inputintr(dev); - spin_unlock_irqrestore(&dmap->lock,flags); -} -EXPORT_SYMBOL(DMAbuf_inputintr); - -void DMAbuf_init(int dev, int dma1, int dma2) -{ - struct audio_operations *adev = audio_devs[dev]; - /* - * NOTE! This routine could be called several times. - */ - - if (adev && adev->dmap_out == NULL) { - if (adev->d == NULL) - panic("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (adev->parent_dev) { /* Use DMA map of the parent dev */ - int parent = adev->parent_dev - 1; - adev->dmap_out = audio_devs[parent]->dmap_out; - adev->dmap_in = audio_devs[parent]->dmap_in; - } else { - adev->dmap_out = adev->dmap_in = &adev->dmaps[0]; - adev->dmap_out->dma = dma1; - if (adev->flags & DMA_DUPLEX) { - adev->dmap_in = &adev->dmaps[1]; - adev->dmap_in->dma = dma2; - } - } - /* Persistent DMA buffers allocated here */ - if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { - if (adev->dmap_in->raw_buf == NULL) - sound_alloc_dmap(adev->dmap_in); - if (adev->dmap_out->raw_buf == NULL) - sound_alloc_dmap(adev->dmap_out); - } - } -} - -/* No kernel lock - DMAbuf_activate_recording protected by global cli/sti */ -static unsigned int poll_input(struct file * file, int dev, poll_table *wait) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_in; - - if (!(adev->open_mode & OPEN_READ)) - return 0; - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - if (dmap->qlen) - return POLLIN | POLLRDNORM; - return 0; - } - if (dmap->dma_mode != DMODE_INPUT) { - if (dmap->dma_mode == DMODE_NONE && - adev->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && adev->go) { - unsigned long flags; - - spin_lock_irqsave(&dmap->lock,flags); - DMAbuf_activate_recording(dev, dmap); - spin_unlock_irqrestore(&dmap->lock,flags); - } - return 0; - } - if (!dmap->qlen) - return 0; - return POLLIN | POLLRDNORM; -} - -static unsigned int poll_output(struct file * file, int dev, poll_table *wait) -{ - struct audio_operations *adev = audio_devs[dev]; - struct dma_buffparms *dmap = adev->dmap_out; - - if (!(adev->open_mode & OPEN_WRITE)) - return 0; - if (dmap->mapping_flags & DMA_MAP_MAPPED) { - if (dmap->qlen) - return POLLOUT | POLLWRNORM; - return 0; - } - if (dmap->dma_mode == DMODE_INPUT) - return 0; - if (dmap->dma_mode == DMODE_NONE) - return POLLOUT | POLLWRNORM; - if (!DMAbuf_space_in_queue(dev)) - return 0; - return POLLOUT | POLLWRNORM; -} - -unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait) -{ - struct audio_operations *adev = audio_devs[dev]; - poll_wait(file, &adev->poll_sleeper, wait); - return poll_input(file, dev, wait) | poll_output(file, dev, wait); -} - -void DMAbuf_deinit(int dev) -{ - struct audio_operations *adev = audio_devs[dev]; - /* This routine is called when driver is being unloaded */ - if (!adev) - return; - - /* Persistent DMA buffers deallocated here */ - if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { - sound_free_dmap(adev->dmap_out); - if (adev->flags & DMA_DUPLEX) - sound_free_dmap(adev->dmap_in); - } -} diff --git a/sound/oss/hex2hex.c b/sound/oss/hex2hex.c deleted file mode 100644 index f76d729b0196..000000000000 --- a/sound/oss/hex2hex.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * hex2hex reads stdin in Intel HEX format and produces an - * (unsigned char) array which contains the bytes and writes it - * to stdout using C syntax - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#define ABANDON(why) { fprintf(stderr, "%s\n", why); exit(1); } -#define MAX_SIZE (256*1024) -unsigned char buf[MAX_SIZE]; - -static int loadhex(FILE *inf, unsigned char *buf) -{ - int l=0, c, i; - - while ((c=getc(inf))!=EOF) - { - if (c == ':') /* Sync with beginning of line */ - { - int n, check; - unsigned char sum; - int addr; - int linetype; - - if (fscanf(inf, "%02x", &n) != 1) - ABANDON("File format error"); - sum = n; - - if (fscanf(inf, "%04x", &addr) != 1) - ABANDON("File format error"); - sum += addr/256; - sum += addr%256; - - if (fscanf(inf, "%02x", &linetype) != 1) - ABANDON("File format error"); - sum += linetype; - - if (linetype != 0) - continue; - - for (i=0;i<n;i++) - { - if (fscanf(inf, "%02x", &c) != 1) - ABANDON("File format error"); - if (addr >= MAX_SIZE) - ABANDON("File too large"); - buf[addr++] = c; - if (addr > l) - l = addr; - sum += c; - } - - if (fscanf(inf, "%02x", &check) != 1) - ABANDON("File format error"); - - sum = ~sum + 1; - if (check != sum) - ABANDON("Line checksum error"); - } - } - - return l; -} - -int main( int argc, const char * argv [] ) -{ - const char * varline; - int i,l; - int id=0; - - if(argv[1] && strcmp(argv[1], "-i")==0) - { - argv++; - argc--; - id=1; - } - if(argv[1]==NULL) - { - fprintf(stderr,"hex2hex: [-i] filename\n"); - exit(1); - } - varline = argv[1]; - l = loadhex(stdin, buf); - - printf("/*\n *\t Computer generated file. Do not edit.\n */\n"); - printf("static int %s_len = %d;\n", varline, l); - printf("static unsigned char %s[] %s = {\n", varline, id?"__initdata":""); - - for (i=0;i<l;i++) - { - if (i) printf(","); - if (i && !(i % 16)) printf("\n"); - printf("0x%02x", buf[i]); - } - - printf("\n};\n\n"); - return 0; -} diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c deleted file mode 100644 index c4b0434c7604..000000000000 --- a/sound/oss/kahlua.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Initialisation code for Cyrix/NatSemi VSA1 softaudio - * - * (C) Copyright 2003 Red Hat Inc <alan@lxorguk.ukuu.org.uk> - * - * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems. - * The older version (VSA1) provides fairly good soundblaster emulation - * although there are a couple of bugs: large DMA buffers break record, - * and the MPU event handling seems suspect. VSA2 allows the native driver - * to control the AC97 audio engine directly and requires a different driver. - * - * Thanks to National Semiconductor for providing the needed information - * on the XpressAudio(tm) internals. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * TO DO: - * Investigate whether we can portably support Cognac (5520) in the - * same manner. - */ - -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/slab.h> - -#include "sound_config.h" - -#include "sb.h" - -/* - * Read a soundblaster compatible mixer register. - * In this case we are actually reading an SMI trap - * not real hardware. - */ - -static u8 mixer_read(unsigned long io, u8 reg) -{ - outb(reg, io + 4); - udelay(20); - reg = inb(io + 5); - udelay(20); - return reg; -} - -static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct address_info *hw_config; - unsigned long base; - void __iomem *mem; - unsigned long io; - u16 map; - u8 irq, dma8, dma16; - int oldquiet; - extern int sb_be_quiet; - - base = pci_resource_start(pdev, 0); - if(base == 0UL) - return 1; - - mem = ioremap(base, 128); - if (!mem) - return 1; - map = readw(mem + 0x18); /* Read the SMI enables */ - iounmap(mem); - - /* Map bits - 0:1 * 0x20 + 0x200 = sb base - 2 sb enable - 3 adlib enable - 5 MPU enable 0x330 - 6 MPU enable 0x300 - - The other bits may be used internally so must be masked */ - - io = 0x220 + 0x20 * (map & 3); - - if(map & (1<<2)) - printk(KERN_INFO "kahlua: XpressAudio at 0x%lx\n", io); - else - return 1; - - if(map & (1<<5)) - printk(KERN_INFO "kahlua: MPU at 0x300\n"); - else if(map & (1<<6)) - printk(KERN_INFO "kahlua: MPU at 0x330\n"); - - irq = mixer_read(io, 0x80) & 0x0F; - dma8 = mixer_read(io, 0x81); - - // printk("IRQ=%x MAP=%x DMA=%x\n", irq, map, dma8); - - if(dma8 & 0x20) - dma16 = 5; - else if(dma8 & 0x40) - dma16 = 6; - else if(dma8 & 0x80) - dma16 = 7; - else - { - printk(KERN_ERR "kahlua: No 16bit DMA enabled.\n"); - return 1; - } - - if(dma8 & 0x01) - dma8 = 0; - else if(dma8 & 0x02) - dma8 = 1; - else if(dma8 & 0x08) - dma8 = 3; - else - { - printk(KERN_ERR "kahlua: No 8bit DMA enabled.\n"); - return 1; - } - - if(irq & 1) - irq = 9; - else if(irq & 2) - irq = 5; - else if(irq & 4) - irq = 7; - else if(irq & 8) - irq = 10; - else - { - printk(KERN_ERR "kahlua: SB IRQ not set.\n"); - return 1; - } - - printk(KERN_INFO "kahlua: XpressAudio on IRQ %d, DMA %d, %d\n", - irq, dma8, dma16); - - hw_config = kzalloc(sizeof(struct address_info), GFP_KERNEL); - if(hw_config == NULL) - { - printk(KERN_ERR "kahlua: out of memory.\n"); - return 1; - } - - pci_set_drvdata(pdev, hw_config); - - hw_config->io_base = io; - hw_config->irq = irq; - hw_config->dma = dma8; - hw_config->dma2 = dma16; - hw_config->name = "Cyrix XpressAudio"; - hw_config->driver_use_1 = SB_NO_MIDI | SB_PCI_IRQ; - - if (!request_region(io, 16, "soundblaster")) - goto err_out_free; - - if(sb_dsp_detect(hw_config, 0, 0, NULL)==0) - { - printk(KERN_ERR "kahlua: audio not responding.\n"); - release_region(io, 16); - goto err_out_free; - } - - oldquiet = sb_be_quiet; - sb_be_quiet = 1; - if(sb_dsp_init(hw_config, THIS_MODULE)) - { - sb_be_quiet = oldquiet; - goto err_out_free; - } - sb_be_quiet = oldquiet; - - return 0; - -err_out_free: - kfree(hw_config); - return 1; -} - -static void remove_one(struct pci_dev *pdev) -{ - struct address_info *hw_config = pci_get_drvdata(pdev); - sb_dsp_unload(hw_config, 0); - kfree(hw_config); -} - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("Kahlua VSA1 PCI Audio"); -MODULE_LICENSE("GPL"); - -/* - * 5530 only. The 5510/5520 decode is different. - */ - -static const struct pci_device_id id_tbl[] = { - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, id_tbl); - -static struct pci_driver kahlua_driver = { - .name = "kahlua", - .id_table = id_tbl, - .probe = probe_one, - .remove = remove_one, -}; - - -static int __init kahlua_init_module(void) -{ - printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n"); - return pci_register_driver(&kahlua_driver); -} - -static void kahlua_cleanup_module(void) -{ - pci_unregister_driver(&kahlua_driver); -} - - -module_init(kahlua_init_module); -module_exit(kahlua_cleanup_module); - diff --git a/sound/oss/midi_ctrl.h b/sound/oss/midi_ctrl.h deleted file mode 100644 index 240d0c719f1e..000000000000 --- a/sound/oss/midi_ctrl.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -static unsigned char ctrl_def_values[128] = -{ - 0x40,0x00,0x40,0x40, 0x40,0x40,0x40,0x7f, /* 0 to 7 */ - 0x40,0x40,0x40,0x7f, 0x40,0x40,0x40,0x40, /* 8 to 15 */ - 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 16 to 23 */ - 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 24 to 31 */ - - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */ - - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 88 to 95 */ - - 0x00,0x00,0x7f,0x7f, 0x7f,0x7f,0x00,0x00, /* 96 to 103 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 104 to 111 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 112 to 119 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 120 to 127 */ -}; diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c deleted file mode 100644 index 2292c230d7e6..000000000000 --- a/sound/oss/midi_synth.c +++ /dev/null @@ -1,712 +0,0 @@ -/* - * sound/oss/midi_synth.c - * - * High level midi sequencer manager for dumb MIDI interfaces. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Andrew Veliath : fixed running status in MIDI input state machine - */ -#define USE_SEQ_MACROS -#define USE_SIMPLE_MACROS - -#include "sound_config.h" - -#define _MIDI_SYNTH_C_ - -#include "midi_synth.h" - -static int midi2synth[MAX_MIDI_DEV]; -static int sysex_state[MAX_MIDI_DEV] = -{0}; -static unsigned char prev_out_status[MAX_MIDI_DEV]; - -#define STORE(cmd) \ -{ \ - int len; \ - unsigned char obuf[8]; \ - cmd; \ - seq_input_event(obuf, len); \ -} - -#define _seqbuf obuf -#define _seqbufptr 0 -#define _SEQ_ADVBUF(x) len=x - -void -do_midi_msg(int synthno, unsigned char *msg, int mlen) -{ - switch (msg[0] & 0xf0) - { - case 0x90: - if (msg[2] != 0) - { - STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - } - msg[2] = 64; - - case 0x80: - STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xA0: - STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xB0: - STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, - msg[1], msg[2])); - break; - - case 0xC0: - STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xD0: - STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xE0: - STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, - (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7))); - break; - - default: - /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ - ; - } -} -EXPORT_SYMBOL(do_midi_msg); - -static void -midi_outc(int midi_dev, int data) -{ - int timeout; - - for (timeout = 0; timeout < 3200; timeout++) - if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff))) - { - if (data & 0x80) /* - * Status byte - */ - prev_out_status[midi_dev] = - (unsigned char) (data & 0xff); /* - * Store for running status - */ - return; /* - * Mission complete - */ - } - /* - * Sorry! No space on buffers. - */ - printk("Midi send timed out\n"); -} - -static int -prefix_cmd(int midi_dev, unsigned char status) -{ - if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) - return 1; - - return midi_devs[midi_dev]->prefix_cmd(midi_dev, status); -} - -static void -midi_synth_input(int orig_dev, unsigned char data) -{ - int dev; - struct midi_input_info *inc; - - static unsigned char len_tab[] = /* # of data bytes following a status - */ - { - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ - }; - - if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) - return; - - if (data == 0xfe) /* Ignore active sensing */ - return; - - dev = midi2synth[orig_dev]; - inc = &midi_devs[orig_dev]->in_info; - - switch (inc->m_state) - { - case MST_INIT: - if (data & 0x80) /* MIDI status byte */ - { - if ((data & 0xf0) == 0xf0) /* Common message */ - { - switch (data) - { - case 0xf0: /* Sysex */ - inc->m_state = MST_SYSEX; - break; /* Sysex */ - - case 0xf1: /* MTC quarter frame */ - case 0xf3: /* Song select */ - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = 1; - inc->m_buf[0] = data; - break; - - case 0xf2: /* Song position pointer */ - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = 2; - inc->m_buf[0] = data; - break; - - default: - inc->m_buf[0] = data; - inc->m_ptr = 1; - do_midi_msg(dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - inc->m_left = 0; - } - } else - { - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = len_tab[(data >> 4) - 8]; - inc->m_buf[0] = inc->m_prev_status = data; - } - } else if (inc->m_prev_status & 0x80) { - /* Data byte (use running status) */ - inc->m_ptr = 2; - inc->m_buf[1] = data; - inc->m_buf[0] = inc->m_prev_status; - inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; - if (inc->m_left > 0) - inc->m_state = MST_DATA; /* Not done yet */ - else { - inc->m_state = MST_INIT; - do_midi_msg(dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - } - } - break; /* MST_INIT */ - - case MST_DATA: - inc->m_buf[inc->m_ptr++] = data; - if (--inc->m_left <= 0) - { - inc->m_state = MST_INIT; - do_midi_msg(dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - } - break; /* MST_DATA */ - - case MST_SYSEX: - if (data == 0xf7) /* Sysex end */ - { - inc->m_state = MST_INIT; - inc->m_left = 0; - inc->m_ptr = 0; - } - break; /* MST_SYSEX */ - - default: - printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); - inc->m_state = MST_INIT; - } -} - -static void -leave_sysex(int dev) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int timeout = 0; - - if (!sysex_state[dev]) - return; - - sysex_state[dev] = 0; - - while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && - timeout < 1000) - timeout++; - - sysex_state[dev] = 0; -} - -static void -midi_synth_output(int dev) -{ - /* - * Currently NOP - */ -} - -int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - /* - * int orig_dev = synth_devs[dev]->midi_dev; - */ - - switch (cmd) { - - case SNDCTL_SYNTH_INFO: - if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info))) - return -EFAULT; - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(midi_synth_ioctl); - -int -midi_synth_kill_note(int dev, int channel, int note, int velocity) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; - - if (note < 0 || note > 127) - return 0; - if (channel < 0 || channel > 15) - return 0; - if (velocity < 0) - velocity = 0; - if (velocity > 127) - velocity = 127; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) - { /* - * Use running status - */ - if (!prefix_cmd(orig_dev, note)) - return 0; - - midi_outc(orig_dev, note); - - if (msg == 0x90) /* - * Running status = Note on - */ - midi_outc(orig_dev, 0); /* - * Note on with velocity 0 == note - * off - */ - else - midi_outc(orig_dev, velocity); - } else - { - if (velocity == 64) - { - if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) - return 0; - midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* - * Note on - */ - midi_outc(orig_dev, note); - midi_outc(orig_dev, 0); /* - * Zero G - */ - } else - { - if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f))) - return 0; - midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* - * Note off - */ - midi_outc(orig_dev, note); - midi_outc(orig_dev, velocity); - } - } - - return 0; -} -EXPORT_SYMBOL(midi_synth_kill_note); - -int -midi_synth_set_instr(int dev, int channel, int instr_no) -{ - int orig_dev = synth_devs[dev]->midi_dev; - - if (instr_no < 0 || instr_no > 127) - instr_no = 0; - if (channel < 0 || channel > 15) - return 0; - - leave_sysex(dev); - - if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f))) - return 0; - midi_outc(orig_dev, 0xc0 | (channel & 0x0f)); /* - * Program change - */ - midi_outc(orig_dev, instr_no); - - return 0; -} -EXPORT_SYMBOL(midi_synth_set_instr); - -int -midi_synth_start_note(int dev, int channel, int note, int velocity) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; - - if (note < 0 || note > 127) - return 0; - if (channel < 0 || channel > 15) - return 0; - if (velocity < 0) - velocity = 0; - if (velocity > 127) - velocity = 127; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (chn == channel && msg == 0x90) - { /* - * Use running status - */ - if (!prefix_cmd(orig_dev, note)) - return 0; - midi_outc(orig_dev, note); - midi_outc(orig_dev, velocity); - } else - { - if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) - return 0; - midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* - * Note on - */ - midi_outc(orig_dev, note); - midi_outc(orig_dev, velocity); - } - return 0; -} -EXPORT_SYMBOL(midi_synth_start_note); - -void -midi_synth_reset(int dev) -{ - - leave_sysex(dev); -} -EXPORT_SYMBOL(midi_synth_reset); - -int -midi_synth_open(int dev, int mode) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int err; - struct midi_input_info *inc; - - if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL) - return -ENXIO; - - midi2synth[orig_dev] = dev; - sysex_state[dev] = 0; - prev_out_status[orig_dev] = 0; - - if ((err = midi_devs[orig_dev]->open(orig_dev, mode, - midi_synth_input, midi_synth_output)) < 0) - return err; - inc = &midi_devs[orig_dev]->in_info; - - /* save_flags(flags); - cli(); - don't know against what irqhandler to protect*/ - inc->m_busy = 0; - inc->m_state = MST_INIT; - inc->m_ptr = 0; - inc->m_left = 0; - inc->m_prev_status = 0x00; - /* restore_flags(flags); */ - - return 1; -} -EXPORT_SYMBOL(midi_synth_open); - -void -midi_synth_close(int dev) -{ - int orig_dev = synth_devs[dev]->midi_dev; - - leave_sysex(dev); - - /* - * Shut up the synths by sending just single active sensing message. - */ - midi_devs[orig_dev]->outputc(orig_dev, 0xfe); - - midi_devs[orig_dev]->close(orig_dev); -} -EXPORT_SYMBOL(midi_synth_close); - -void -midi_synth_hw_control(int dev, unsigned char *event) -{ -} -EXPORT_SYMBOL(midi_synth_hw_control); - -int -midi_synth_load_patch(int dev, int format, const char __user *addr, - int count, int pmgr_flag) -{ - int orig_dev = synth_devs[dev]->midi_dev; - - struct sysex_info sysex; - int i; - unsigned long left, src_offs, eox_seen = 0; - int first_byte = 1; - int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; - - leave_sysex(dev); - - if (!prefix_cmd(orig_dev, 0xf0)) - return 0; - - /* Invalid patch format */ - if (format != SYSEX_PATCH) - return -EINVAL; - - /* Patch header too short */ - if (count < hdr_size) - return -EINVAL; - - count -= hdr_size; - - /* - * Copy the header from user space - */ - - if (copy_from_user(&sysex, addr, hdr_size)) - return -EFAULT; - - /* Sysex record too short */ - if ((unsigned)count < (unsigned)sysex.len) - sysex.len = count; - - left = sysex.len; - src_offs = 0; - - for (i = 0; i < left && !signal_pending(current); i++) - { - unsigned char data; - - if (get_user(data, - (unsigned char __user *)(addr + hdr_size + i))) - return -EFAULT; - - eox_seen = (i > 0 && data & 0x80); /* End of sysex */ - - if (eox_seen && data != 0xf7) - data = 0xf7; - - if (i == 0) - { - if (data != 0xf0) - { - printk(KERN_WARNING "midi_synth: Sysex start missing\n"); - return -EINVAL; - } - } - while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && - !signal_pending(current)) - schedule(); - - if (!first_byte && data & 0x80) - return 0; - first_byte = 0; - } - - if (!eox_seen) - midi_outc(orig_dev, 0xf7); - return 0; -} -EXPORT_SYMBOL(midi_synth_load_patch); - -void midi_synth_panning(int dev, int channel, int pressure) -{ -} -EXPORT_SYMBOL(midi_synth_panning); - -void midi_synth_aftertouch(int dev, int channel, int pressure) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; - - if (pressure < 0 || pressure > 127) - return; - if (channel < 0 || channel > 15) - return; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (msg != 0xd0 || chn != channel) /* - * Test for running status - */ - { - if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f))) - return; - midi_outc(orig_dev, 0xd0 | (channel & 0x0f)); /* - * Channel pressure - */ - } else if (!prefix_cmd(orig_dev, pressure)) - return; - - midi_outc(orig_dev, pressure); -} -EXPORT_SYMBOL(midi_synth_aftertouch); - -void -midi_synth_controller(int dev, int channel, int ctrl_num, int value) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int chn, msg; - - if (ctrl_num < 0 || ctrl_num > 127) - return; - if (channel < 0 || channel > 15) - return; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (msg != 0xb0 || chn != channel) - { - if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f))) - return; - midi_outc(orig_dev, 0xb0 | (channel & 0x0f)); - } else if (!prefix_cmd(orig_dev, ctrl_num)) - return; - - midi_outc(orig_dev, ctrl_num); - midi_outc(orig_dev, value & 0x7f); -} -EXPORT_SYMBOL(midi_synth_controller); - -void -midi_synth_bender(int dev, int channel, int value) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int msg, prev_chn; - - if (channel < 0 || channel > 15) - return; - - if (value < 0 || value > 16383) - return; - - leave_sysex(dev); - - msg = prev_out_status[orig_dev] & 0xf0; - prev_chn = prev_out_status[orig_dev] & 0x0f; - - if (msg != 0xd0 || prev_chn != channel) /* - * Test for running status - */ - { - if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f))) - return; - midi_outc(orig_dev, 0xe0 | (channel & 0x0f)); - } else if (!prefix_cmd(orig_dev, value & 0x7f)) - return; - - midi_outc(orig_dev, value & 0x7f); - midi_outc(orig_dev, (value >> 7) & 0x7f); -} -EXPORT_SYMBOL(midi_synth_bender); - -void -midi_synth_setup_voice(int dev, int voice, int channel) -{ -} -EXPORT_SYMBOL(midi_synth_setup_voice); - -int -midi_synth_send_sysex(int dev, unsigned char *bytes, int len) -{ - int orig_dev = synth_devs[dev]->midi_dev; - int i; - - for (i = 0; i < len; i++) - { - switch (bytes[i]) - { - case 0xf0: /* Start sysex */ - if (!prefix_cmd(orig_dev, 0xf0)) - return 0; - sysex_state[dev] = 1; - break; - - case 0xf7: /* End sysex */ - if (!sysex_state[dev]) /* Orphan sysex end */ - return 0; - sysex_state[dev] = 0; - break; - - default: - if (!sysex_state[dev]) - return 0; - - if (bytes[i] & 0x80) /* Error. Another message before sysex end */ - { - bytes[i] = 0xf7; /* Sysex end */ - sysex_state[dev] = 0; - } - } - - if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i])) - { -/* - * Hardware level buffer is full. Abort the sysex message. - */ - - int timeout = 0; - - bytes[i] = 0xf7; - sysex_state[dev] = 0; - - while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) && - timeout < 1000) - timeout++; - } - if (!sysex_state[dev]) - return 0; - } - - return 0; -} -EXPORT_SYMBOL(midi_synth_send_sysex); - diff --git a/sound/oss/midi_synth.h b/sound/oss/midi_synth.h deleted file mode 100644 index 1cf676c7510e..000000000000 --- a/sound/oss/midi_synth.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -int midi_synth_ioctl (int dev, - unsigned int cmd, void __user * arg); -int midi_synth_kill_note (int dev, int channel, int note, int velocity); -int midi_synth_set_instr (int dev, int channel, int instr_no); -int midi_synth_start_note (int dev, int channel, int note, int volume); -void midi_synth_reset (int dev); -int midi_synth_open (int dev, int mode); -void midi_synth_close (int dev); -void midi_synth_hw_control (int dev, unsigned char *event); -int midi_synth_load_patch (int dev, int format, const char __user * addr, - int count, int pmgr_flag); -void midi_synth_panning (int dev, int channel, int pressure); -void midi_synth_aftertouch (int dev, int channel, int pressure); -void midi_synth_controller (int dev, int channel, int ctrl_num, int value); -void midi_synth_bender (int dev, int chn, int value); -void midi_synth_setup_voice (int dev, int voice, int chn); -int midi_synth_send_sysex(int dev, unsigned char *bytes,int len); - -#ifndef _MIDI_SYNTH_C_ -static struct synth_info std_synth_info = -{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS}; - -static struct synth_operations std_midi_synth = -{ - .owner = THIS_MODULE, - .id = "MIDI", - .info = &std_synth_info, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_MIDI, - .synth_subtype = 0, - .open = midi_synth_open, - .close = midi_synth_close, - .ioctl = midi_synth_ioctl, - .kill_note = midi_synth_kill_note, - .start_note = midi_synth_start_note, - .set_instr = midi_synth_set_instr, - .reset = midi_synth_reset, - .hw_control = midi_synth_hw_control, - .load_patch = midi_synth_load_patch, - .aftertouch = midi_synth_aftertouch, - .controller = midi_synth_controller, - .panning = midi_synth_panning, - .bender = midi_synth_bender, - .setup_voice = midi_synth_setup_voice, - .send_sysex = midi_synth_send_sysex -}; -#endif diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c deleted file mode 100644 index 701c7625c971..000000000000 --- a/sound/oss/midibuf.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * sound/oss/midibuf.c - * - * Device file manager for /dev/midi# - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - */ -#include <linux/stddef.h> -#include <linux/kmod.h> -#include <linux/spinlock.h> -#include <linux/sched/signal.h> - -#define MIDIBUF_C - -#include "sound_config.h" - - -/* - * Don't make MAX_QUEUE_SIZE larger than 4000 - */ - -#define MAX_QUEUE_SIZE 4000 - -static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV]; -static wait_queue_head_t input_sleeper[MAX_MIDI_DEV]; - -struct midi_buf -{ - int len, head, tail; - unsigned char queue[MAX_QUEUE_SIZE]; -}; - -struct midi_parms -{ - long prech_timeout; /* - * Timeout before the first ch - */ -}; - -static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL}; -static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL}; -static struct midi_parms parms[MAX_MIDI_DEV]; - -static void midi_poll(unsigned long dummy); - - -static DEFINE_TIMER(poll_timer, midi_poll, 0, 0); - -static volatile int open_devs; -static DEFINE_SPINLOCK(lock); - -#define DATA_AVAIL(q) (q->len) -#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len) - -#define QUEUE_BYTE(q, data) \ - if (SPACE_AVAIL(q)) \ - { \ - unsigned long flags; \ - spin_lock_irqsave(&lock, flags); \ - q->queue[q->tail] = (data); \ - q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \ - spin_unlock_irqrestore(&lock, flags); \ - } - -#define REMOVE_BYTE(q, data) \ - if (DATA_AVAIL(q)) \ - { \ - unsigned long flags; \ - spin_lock_irqsave(&lock, flags); \ - data = q->queue[q->head]; \ - q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \ - spin_unlock_irqrestore(&lock, flags); \ - } - -static void drain_midi_queue(int dev) -{ - - /* - * Give the Midi driver time to drain its output queues - */ - - if (midi_devs[dev]->buffer_status != NULL) - wait_event_interruptible_timeout(midi_sleeper[dev], - !midi_devs[dev]->buffer_status(dev), HZ/10); -} - -static void midi_input_intr(int dev, unsigned char data) -{ - if (midi_in_buf[dev] == NULL) - return; - - if (data == 0xfe) /* - * Active sensing - */ - return; /* - * Ignore - */ - - if (SPACE_AVAIL(midi_in_buf[dev])) { - QUEUE_BYTE(midi_in_buf[dev], data); - wake_up(&input_sleeper[dev]); - } -} - -static void midi_output_intr(int dev) -{ - /* - * Currently NOP - */ -} - -static void midi_poll(unsigned long dummy) -{ - unsigned long flags; - int dev; - - spin_lock_irqsave(&lock, flags); - if (open_devs) - { - for (dev = 0; dev < num_midis; dev++) - if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) - { - while (DATA_AVAIL(midi_out_buf[dev])) - { - int ok; - int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; - - spin_unlock_irqrestore(&lock,flags);/* Give some time to others */ - ok = midi_devs[dev]->outputc(dev, c); - spin_lock_irqsave(&lock, flags); - if (!ok) - break; - midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; - midi_out_buf[dev]->len--; - } - - if (DATA_AVAIL(midi_out_buf[dev]) < 100) - wake_up(&midi_sleeper[dev]); - } - poll_timer.expires = (1) + jiffies; - add_timer(&poll_timer); - /* - * Come back later - */ - } - spin_unlock_irqrestore(&lock, flags); -} - -int MIDIbuf_open(int dev, struct file *file) -{ - int mode, err; - - dev = dev >> 4; - mode = translate_mode(file); - - if (num_midis > MAX_MIDI_DEV) - { - printk(KERN_ERR "midi: Too many midi interfaces\n"); - num_midis = MAX_MIDI_DEV; - } - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - return -ENXIO; - /* - * Interrupts disabled. Be careful - */ - - module_put(midi_devs[dev]->owner); - - if ((err = midi_devs[dev]->open(dev, mode, - midi_input_intr, midi_output_intr)) < 0) - return err; - - parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT; - midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf)); - - if (midi_in_buf[dev] == NULL) - { - printk(KERN_WARNING "midi: Can't allocate buffer\n"); - midi_devs[dev]->close(dev); - return -EIO; - } - midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - - midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf)); - - if (midi_out_buf[dev] == NULL) - { - printk(KERN_WARNING "midi: Can't allocate buffer\n"); - midi_devs[dev]->close(dev); - vfree(midi_in_buf[dev]); - midi_in_buf[dev] = NULL; - return -EIO; - } - midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; - open_devs++; - - init_waitqueue_head(&midi_sleeper[dev]); - init_waitqueue_head(&input_sleeper[dev]); - - if (open_devs < 2) /* This was first open */ - { - poll_timer.expires = 1 + jiffies; - add_timer(&poll_timer); /* Start polling */ - } - return err; -} - -void MIDIbuf_release(int dev, struct file *file) -{ - int mode; - - dev = dev >> 4; - mode = translate_mode(file); - - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - return; - - /* - * Wait until the queue is empty - */ - - if (mode != OPEN_READ) - { - midi_devs[dev]->outputc(dev, 0xfe); /* - * Active sensing to shut the - * devices - */ - - wait_event_interruptible(midi_sleeper[dev], - !DATA_AVAIL(midi_out_buf[dev])); - /* - * Sync - */ - - drain_midi_queue(dev); /* - * Ensure the output queues are empty - */ - } - - midi_devs[dev]->close(dev); - - open_devs--; - if (open_devs == 0) - del_timer_sync(&poll_timer); - vfree(midi_in_buf[dev]); - vfree(midi_out_buf[dev]); - midi_in_buf[dev] = NULL; - midi_out_buf[dev] = NULL; - - module_put(midi_devs[dev]->owner); -} - -int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count) -{ - int c, n, i; - unsigned char tmp_data; - - dev = dev >> 4; - - if (!count) - return 0; - - c = 0; - - while (c < count) - { - n = SPACE_AVAIL(midi_out_buf[dev]); - - if (n == 0) { /* - * No space just now. - */ - - if (file->f_flags & O_NONBLOCK) { - c = -EAGAIN; - goto out; - } - - if (wait_event_interruptible(midi_sleeper[dev], - SPACE_AVAIL(midi_out_buf[dev]))) - { - c = -EINTR; - goto out; - } - n = SPACE_AVAIL(midi_out_buf[dev]); - } - if (n > (count - c)) - n = count - c; - - for (i = 0; i < n; i++) - { - /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */ - /* yes, think the same, so I removed the cli() brackets - QUEUE_BYTE is protected against interrupts */ - if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) { - c = -EFAULT; - goto out; - } - QUEUE_BYTE(midi_out_buf[dev], tmp_data); - c++; - } - } -out: - return c; -} - - -int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count) -{ - int n, c = 0; - unsigned char tmp_data; - - dev = dev >> 4; - - if (!DATA_AVAIL(midi_in_buf[dev])) { /* - * No data yet, wait - */ - if (file->f_flags & O_NONBLOCK) { - c = -EAGAIN; - goto out; - } - wait_event_interruptible_timeout(input_sleeper[dev], - DATA_AVAIL(midi_in_buf[dev]), - parms[dev].prech_timeout); - - if (signal_pending(current)) - c = -EINTR; /* The user is getting restless */ - } - if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /* - * Got some bytes - */ - { - n = DATA_AVAIL(midi_in_buf[dev]); - if (n > count) - n = count; - c = 0; - - while (c < n) - { - char *fixit; - REMOVE_BYTE(midi_in_buf[dev], tmp_data); - fixit = (char *) &tmp_data; - /* BROKE BROKE BROKE */ - /* yes removed the cli() brackets again - should q->len,tail&head be atomic_t? */ - if (copy_to_user(&(buf)[c], fixit, 1)) { - c = -EFAULT; - goto out; - } - c++; - } - } -out: - return c; -} - -int MIDIbuf_ioctl(int dev, struct file *file, - unsigned int cmd, void __user *arg) -{ - int val; - - dev = dev >> 4; - - if (((cmd >> 8) & 0xff) == 'C') - { - if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ - return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0); -/* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/ - return -ENXIO; - } - else - { - switch (cmd) - { - case SNDCTL_MIDI_PRETIME: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - if (val < 0) - val = 0; - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return put_user(val, (int __user *)arg); - - default: - if (!midi_devs[dev]->ioctl) - return -EINVAL; - return midi_devs[dev]->ioctl(dev, cmd, arg); - } - } -} - -/* No kernel lock - fine */ -unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait) -{ - unsigned int mask = 0; - - dev = dev >> 4; - - /* input */ - poll_wait(file, &input_sleeper[dev], wait); - if (DATA_AVAIL(midi_in_buf[dev])) - mask |= POLLIN | POLLRDNORM; - - /* output */ - poll_wait(file, &midi_sleeper[dev], wait); - if (!SPACE_AVAIL(midi_out_buf[dev])) - mask |= POLLOUT | POLLWRNORM; - - return mask; -} - - -int MIDIbuf_avail(int dev) -{ - if (midi_in_buf[dev]) - return DATA_AVAIL (midi_in_buf[dev]); - return 0; -} -EXPORT_SYMBOL(MIDIbuf_avail); - diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c deleted file mode 100644 index 20e8fa46f647..000000000000 --- a/sound/oss/mpu401.c +++ /dev/null @@ -1,1804 +0,0 @@ -/* - * sound/oss/mpu401.c - * - * The low level driver for Roland MPU-401 compatible Midi cards. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, use normal request_irq, use dev_id - * Bartlomiej Zolnierkiewicz removed some __init to allow using many drivers - * Chris Rankin Update the module-usage counter for the coprocessor - * Zwane Mwaikambo Changed attach/unload resource freeing - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#define USE_SEQ_MACROS -#define USE_SIMPLE_MACROS - -#include "sound_config.h" - -#include "coproc.h" -#include "mpu401.h" - -static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; - -struct mpu_config -{ - int base; /* - * I/O base - */ - int irq; - int opened; /* - * Open mode - */ - int devno; - int synthno; - int uart_mode; - int initialized; - int mode; -#define MODE_MIDI 1 -#define MODE_SYNTH 2 - unsigned char version, revision; - unsigned int capabilities; -#define MPU_CAP_INTLG 0x10000000 -#define MPU_CAP_SYNC 0x00000010 -#define MPU_CAP_FSK 0x00000020 -#define MPU_CAP_CLS 0x00000040 -#define MPU_CAP_SMPTE 0x00000080 -#define MPU_CAP_2PORT 0x00000001 - int timer_flag; - -#define MBUF_MAX 10 -#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \ - {printk( "MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;} - int m_busy; - unsigned char m_buf[MBUF_MAX]; - int m_ptr; - int m_state; - int m_left; - unsigned char last_status; - void (*inputintr) (int dev, unsigned char data); - int shared_irq; - int *osp; - spinlock_t lock; - }; - -#define DATAPORT(base) (base) -#define COMDPORT(base) (base+1) -#define STATPORT(base) (base+1) - - -static void mpu401_close(int dev); - -static inline int mpu401_status(struct mpu_config *devc) -{ - return inb(STATPORT(devc->base)); -} - -#define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL)) -#define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY)) - -static inline void write_command(struct mpu_config *devc, unsigned char cmd) -{ - outb(cmd, COMDPORT(devc->base)); -} - -static inline int read_data(struct mpu_config *devc) -{ - return inb(DATAPORT(devc->base)); -} - -static inline void write_data(struct mpu_config *devc, unsigned char byte) -{ - outb(byte, DATAPORT(devc->base)); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static struct mpu_config dev_conf[MAX_MIDI_DEV]; - -static int n_mpu_devs; - -static int reset_mpu401(struct mpu_config *devc); -static void set_uart_mode(int dev, struct mpu_config *devc, int arg); - -static int mpu_timer_init(int midi_dev); -static void mpu_timer_interrupt(void); -static void timer_ext_event(struct mpu_config *devc, int event, int parm); - -static struct synth_info mpu_synth_info_proto = { - "MPU-401 MIDI interface", - 0, - SYNTH_TYPE_MIDI, - MIDI_TYPE_MPU401, - 0, 128, - 0, 128, - SYNTH_CAP_INPUT -}; - -static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; - -/* - * States for the input scanner - */ - -#define ST_INIT 0 /* Ready for timing byte or msg */ -#define ST_TIMED 1 /* Leading timing byte rcvd */ -#define ST_DATABYTE 2 /* Waiting for (nr_left) data bytes */ - -#define ST_SYSMSG 100 /* System message (sysx etc). */ -#define ST_SYSEX 101 /* System exclusive msg */ -#define ST_MTC 102 /* Midi Time Code (MTC) qframe msg */ -#define ST_SONGSEL 103 /* Song select */ -#define ST_SONGPOS 104 /* Song position pointer */ - -static unsigned char len_tab[] = /* # of data bytes following a status - */ -{ - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ -}; - -#define STORE(cmd) \ -{ \ - int len; \ - unsigned char obuf[8]; \ - cmd; \ - seq_input_event(obuf, len); \ -} - -#define _seqbuf obuf -#define _seqbufptr 0 -#define _SEQ_ADVBUF(x) len=x - -static int mpu_input_scanner(struct mpu_config *devc, unsigned char midic) -{ - - switch (devc->m_state) - { - case ST_INIT: - switch (midic) - { - case 0xf8: - /* Timer overflow */ - break; - - case 0xfc: - printk("<all end>"); - break; - - case 0xfd: - if (devc->timer_flag) - mpu_timer_interrupt(); - break; - - case 0xfe: - return MPU_ACK; - - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - printk("<Trk data rq #%d>", midic & 0x0f); - break; - - case 0xf9: - printk("<conductor rq>"); - break; - - case 0xff: - devc->m_state = ST_SYSMSG; - break; - - default: - if (midic <= 0xef) - { - /* printk( "mpu time: %d ", midic); */ - devc->m_state = ST_TIMED; - } - else - printk("<MPU: Unknown event %02x> ", midic); - } - break; - - case ST_TIMED: - { - int msg = ((int) (midic & 0xf0) >> 4); - - devc->m_state = ST_DATABYTE; - - if (msg < 8) /* Data byte */ - { - /* printk( "midi msg (running status) "); */ - msg = ((int) (devc->last_status & 0xf0) >> 4); - msg -= 8; - devc->m_left = len_tab[msg] - 1; - - devc->m_ptr = 2; - devc->m_buf[0] = devc->last_status; - devc->m_buf[1] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - } - else if (msg == 0xf) /* MPU MARK */ - { - devc->m_state = ST_INIT; - - switch (midic) - { - case 0xf8: - /* printk( "NOP "); */ - break; - - case 0xf9: - /* printk( "meas end "); */ - break; - - case 0xfc: - /* printk( "data end "); */ - break; - - default: - printk("Unknown MPU mark %02x\n", midic); - } - } - else - { - devc->last_status = midic; - /* printk( "midi msg "); */ - msg -= 8; - devc->m_left = len_tab[msg]; - - devc->m_ptr = 1; - devc->m_buf[0] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - } - } - break; - - case ST_SYSMSG: - switch (midic) - { - case 0xf0: - printk("<SYX>"); - devc->m_state = ST_SYSEX; - break; - - case 0xf1: - devc->m_state = ST_MTC; - break; - - case 0xf2: - devc->m_state = ST_SONGPOS; - devc->m_ptr = 0; - break; - - case 0xf3: - devc->m_state = ST_SONGSEL; - break; - - case 0xf6: - /* printk( "tune_request\n"); */ - devc->m_state = ST_INIT; - break; - - /* - * Real time messages - */ - case 0xf8: - /* midi clock */ - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_CLOCK, 0); - break; - - case 0xfA: - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_START, 0); - break; - - case 0xFB: - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_CONTINUE, 0); - break; - - case 0xFC: - devc->m_state = ST_INIT; - timer_ext_event(devc, TMR_STOP, 0); - break; - - case 0xFE: - /* active sensing */ - devc->m_state = ST_INIT; - break; - - case 0xff: - /* printk( "midi hard reset"); */ - devc->m_state = ST_INIT; - break; - - default: - printk("unknown MIDI sysmsg %0x\n", midic); - devc->m_state = ST_INIT; - } - break; - - case ST_MTC: - devc->m_state = ST_INIT; - printk("MTC frame %x02\n", midic); - break; - - case ST_SYSEX: - if (midic == 0xf7) - { - printk("<EOX>"); - devc->m_state = ST_INIT; - } - else - printk("%02x ", midic); - break; - - case ST_SONGPOS: - BUFTEST(devc); - devc->m_buf[devc->m_ptr++] = midic; - if (devc->m_ptr == 2) - { - devc->m_state = ST_INIT; - devc->m_ptr = 0; - timer_ext_event(devc, TMR_SPP, - ((devc->m_buf[1] & 0x7f) << 7) | - (devc->m_buf[0] & 0x7f)); - } - break; - - case ST_DATABYTE: - BUFTEST(devc); - devc->m_buf[devc->m_ptr++] = midic; - if ((--devc->m_left) <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - break; - - default: - printk("Bad state %d ", devc->m_state); - devc->m_state = ST_INIT; - } - return 1; -} - -static void mpu401_input_loop(struct mpu_config *devc) -{ - unsigned long flags; - int busy; - int n; - - spin_lock_irqsave(&devc->lock,flags); - busy = devc->m_busy; - devc->m_busy = 1; - spin_unlock_irqrestore(&devc->lock,flags); - - if (busy) /* Already inside the scanner */ - return; - - n = 50; - - while (input_avail(devc) && n-- > 0) - { - unsigned char c = read_data(devc); - - if (devc->mode == MODE_SYNTH) - { - mpu_input_scanner(devc, c); - } - else if (devc->opened & OPEN_READ && devc->inputintr != NULL) - devc->inputintr(devc->devno, c); - } - devc->m_busy = 0; -} - -static irqreturn_t mpuintr(int irq, void *dev_id) -{ - struct mpu_config *devc; - int dev = (int)(unsigned long) dev_id; - int handled = 0; - - devc = &dev_conf[dev]; - - if (input_avail(devc)) - { - handled = 1; - if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) - mpu401_input_loop(devc); - else - { - /* Dummy read (just to acknowledge the interrupt) */ - read_data(devc); - } - } - return IRQ_RETVAL(handled); -} - -static int mpu401_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - int err; - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - return -ENXIO; - - devc = &dev_conf[dev]; - - if (devc->opened) - return -EBUSY; - /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. - */ - - if (!devc->initialized) - { - if (mpu401_status(devc) == 0xff) /* Bus float */ - { - printk(KERN_ERR "mpu401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401(devc); - } - - if ( (coprocessor = midi_devs[dev]->coproc) != NULL ) - { - if (!try_module_get(coprocessor->owner)) { - mpu401_close(dev); - return -ENODEV; - } - - if ((err = coprocessor->open(coprocessor->devc, COPR_MIDI)) < 0) - { - printk(KERN_WARNING "MPU-401: Can't access coprocessor device\n"); - mpu401_close(dev); - return err; - } - } - - set_uart_mode(dev, devc, 1); - devc->mode = MODE_MIDI; - devc->synthno = 0; - - mpu401_input_loop(devc); - - devc->inputintr = input; - devc->opened = mode; - - return 0; -} - -static void mpu401_close(int dev) -{ - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - devc = &dev_conf[dev]; - if (devc->uart_mode) - reset_mpu401(devc); /* - * This disables the UART mode - */ - devc->mode = 0; - devc->inputintr = NULL; - - coprocessor = midi_devs[dev]->coproc; - if (coprocessor) { - coprocessor->close(coprocessor->devc, COPR_MIDI); - module_put(coprocessor->owner); - } - devc->opened = 0; -} - -static int mpu401_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - - struct mpu_config *devc; - - devc = &dev_conf[dev]; - - /* - * Sometimes it takes about 30000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - spin_lock_irqsave(&devc->lock,flags); - if (!output_ready(devc)) - { - printk(KERN_WARNING "mpu401: Send data timeout\n"); - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - write_data(devc, midi_byte); - spin_unlock_irqrestore(&devc->lock,flags); - return 1; -} - -static int mpu401_command(int dev, mpu_command_rec * cmd) -{ - int i, timeout, ok; - unsigned long flags; - struct mpu_config *devc; - - devc = &dev_conf[dev]; - - if (devc->uart_mode) /* - * Not possible in UART mode - */ - { - printk(KERN_WARNING "mpu401: commands not possible in the UART mode\n"); - return -EINVAL; - } - /* - * Test for input since pending input seems to block the output. - */ - if (input_avail(devc)) - mpu401_input_loop(devc); - - /* - * Sometimes it takes about 50000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - timeout = 50000; -retry: - if (timeout-- <= 0) - { - printk(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; - } - spin_lock_irqsave(&devc->lock,flags); - - if (!output_ready(devc)) - { - spin_unlock_irqrestore(&devc->lock,flags); - goto retry; - } - write_command(devc, cmd->cmd); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - { - if (input_avail(devc)) - { - if (devc->opened && devc->mode == MODE_SYNTH) - { - if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK) - ok = 1; - } - else - { - /* Device is not currently open. Use simpler method */ - if (read_data(devc) == MPU_ACK) - ok = 1; - } - } - } - if (!ok) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -EIO; - } - if (cmd->nr_args) - { - for (i = 0; i < cmd->nr_args; i++) - { - for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--); - - if (!mpu401_out(dev, cmd->data[i])) - { - spin_unlock_irqrestore(&devc->lock,flags); - printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; - } - } - } - cmd->data[0] = 0; - - if (cmd->nr_returns) - { - for (i = 0; i < cmd->nr_returns; i++) - { - ok = 0; - for (timeout = 5000; timeout > 0 && !ok; timeout--) - if (input_avail(devc)) - { - cmd->data[i] = read_data(devc); - ok = 1; - } - if (!ok) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -EIO; - } - } - } - spin_unlock_irqrestore(&devc->lock,flags); - return 0; -} - -static int mpu_cmd(int dev, int cmd, int data) -{ - int ret; - - static mpu_command_rec rec; - - rec.cmd = cmd & 0xff; - rec.nr_args = ((cmd & 0xf0) == 0xE0); - rec.nr_returns = ((cmd & 0xf0) == 0xA0); - rec.data[0] = data & 0xff; - - if ((ret = mpu401_command(dev, &rec)) < 0) - return ret; - return (unsigned char) rec.data[0]; -} - -static int mpu401_prefix_cmd(int dev, unsigned char status) -{ - struct mpu_config *devc = &dev_conf[dev]; - - if (devc->uart_mode) - return 1; - - if (status < 0xf0) - { - if (mpu_cmd(dev, 0xD0, 0) < 0) - return 0; - return 1; - } - switch (status) - { - case 0xF0: - if (mpu_cmd(dev, 0xDF, 0) < 0) - return 0; - return 1; - - default: - return 0; - } -} - -static int mpu401_start_read(int dev) -{ - return 0; -} - -static int mpu401_end_read(int dev) -{ - return 0; -} - -static int mpu401_ioctl(int dev, unsigned cmd, void __user *arg) -{ - struct mpu_config *devc; - mpu_command_rec rec; - int val, ret; - - devc = &dev_conf[dev]; - switch (cmd) - { - case SNDCTL_MIDI_MPUMODE: - if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */ - printk(KERN_WARNING "mpu401: Intelligent mode not supported by the HW\n"); - return -EINVAL; - } - if (get_user(val, (int __user *)arg)) - return -EFAULT; - set_uart_mode(dev, devc, !val); - return 0; - - case SNDCTL_MIDI_MPUCMD: - if (copy_from_user(&rec, arg, sizeof(rec))) - return -EFAULT; - if ((ret = mpu401_command(dev, &rec)) < 0) - return ret; - if (copy_to_user(arg, &rec, sizeof(rec))) - return -EFAULT; - return 0; - - default: - return -EINVAL; - } -} - -static void mpu401_kick(int dev) -{ -} - -static int mpu401_buffer_status(int dev) -{ - return 0; /* - * No data in buffers - */ -} - -static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int midi_dev; - struct mpu_config *devc; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL) - return -ENXIO; - - devc = &dev_conf[midi_dev]; - - switch (cmd) - { - - case SNDCTL_SYNTH_INFO: - if (copy_to_user(arg, &mpu_synth_info[midi_dev], - sizeof(struct synth_info))) - return -EFAULT; - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - - default: - return -EINVAL; - } -} - -static int mpu_synth_open(int dev, int mode) -{ - int midi_dev, err; - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - midi_dev = synth_devs[dev]->midi_dev; - - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) - return -ENXIO; - - devc = &dev_conf[midi_dev]; - - /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. - */ - - if (!devc->initialized) - { - if (mpu401_status(devc) == 0xff) /* Bus float */ - { - printk(KERN_ERR "mpu401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401(devc); - } - if (devc->opened) - return -EBUSY; - devc->mode = MODE_SYNTH; - devc->synthno = dev; - - devc->inputintr = NULL; - - coprocessor = midi_devs[midi_dev]->coproc; - if (coprocessor) { - if (!try_module_get(coprocessor->owner)) - return -ENODEV; - - if ((err = coprocessor->open(coprocessor->devc, COPR_MIDI)) < 0) - { - printk(KERN_WARNING "mpu401: Can't access coprocessor device\n"); - return err; - } - } - devc->opened = mode; - reset_mpu401(devc); - - if (mode & OPEN_READ) - { - mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */ - mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ - mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */ - } - return 0; -} - -static void mpu_synth_close(int dev) -{ - int midi_dev; - struct mpu_config *devc; - struct coproc_operations *coprocessor; - - midi_dev = synth_devs[dev]->midi_dev; - - devc = &dev_conf[midi_dev]; - mpu_cmd(midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ - mpu_cmd(midi_dev, 0x8a, 0); /* Disable data in stopped mode */ - - devc->inputintr = NULL; - - coprocessor = midi_devs[midi_dev]->coproc; - if (coprocessor) { - coprocessor->close(coprocessor->devc, COPR_MIDI); - module_put(coprocessor->owner); - } - devc->opened = 0; - devc->mode = 0; -} - -#define MIDI_SYNTH_NAME "MPU-401 UART Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct synth_operations mpu401_synth_proto = -{ - .owner = THIS_MODULE, - .id = "MPU401", - .info = NULL, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_MIDI, - .synth_subtype = 0, - .open = mpu_synth_open, - .close = mpu_synth_close, - .ioctl = mpu_synth_ioctl, - .kill_note = midi_synth_kill_note, - .start_note = midi_synth_start_note, - .set_instr = midi_synth_set_instr, - .reset = midi_synth_reset, - .hw_control = midi_synth_hw_control, - .load_patch = midi_synth_load_patch, - .aftertouch = midi_synth_aftertouch, - .controller = midi_synth_controller, - .panning = midi_synth_panning, - .bender = midi_synth_bender, - .setup_voice = midi_synth_setup_voice, - .send_sysex = midi_synth_send_sysex -}; - -static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV]; - -static struct midi_operations mpu401_midi_proto = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - .in_info = {0}, - .open = mpu401_open, - .close = mpu401_close, - .ioctl = mpu401_ioctl, - .outputc = mpu401_out, - .start_read = mpu401_start_read, - .end_read = mpu401_end_read, - .kick = mpu401_kick, - .buffer_status = mpu401_buffer_status, - .prefix_cmd = mpu401_prefix_cmd -}; - -static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; - -static void mpu401_chk_version(int n, struct mpu_config *devc) -{ - int tmp; - - devc->version = devc->revision = 0; - - tmp = mpu_cmd(n, 0xAC, 0); - if (tmp < 0) - return; - if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ - return; - devc->version = tmp; - - if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) { - devc->version = 0; - return; - } - devc->revision = tmp; -} - -int attach_mpu401(struct address_info *hw_config, struct module *owner) -{ - unsigned long flags; - char revision_char; - - int m, ret; - struct mpu_config *devc; - - hw_config->slots[1] = -1; - m = sound_alloc_mididev(); - if (m == -1) - { - printk(KERN_WARNING "MPU-401: Too many midi devices detected\n"); - ret = -ENOMEM; - goto out_err; - } - devc = &dev_conf[m]; - devc->base = hw_config->io_base; - devc->osp = hw_config->osp; - devc->irq = hw_config->irq; - devc->opened = 0; - devc->uart_mode = 0; - devc->initialized = 0; - devc->version = 0; - devc->revision = 0; - devc->capabilities = 0; - devc->timer_flag = 0; - devc->m_busy = 0; - devc->m_state = ST_INIT; - devc->shared_irq = hw_config->always_detect; - spin_lock_init(&devc->lock); - - if (devc->irq < 0) - { - devc->irq *= -1; - devc->shared_irq = 1; - } - - if (!hw_config->always_detect) - { - /* Verify the hardware again */ - if (!reset_mpu401(devc)) - { - printk(KERN_WARNING "mpu401: Device didn't respond\n"); - ret = -ENODEV; - goto out_mididev; - } - if (!devc->shared_irq) - { - if (request_irq(devc->irq, mpuintr, 0, "mpu401", - hw_config) < 0) - { - printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq); - ret = -ENOMEM; - goto out_mididev; - } - } - spin_lock_irqsave(&devc->lock,flags); - mpu401_chk_version(m, devc); - if (devc->version == 0) - mpu401_chk_version(m, devc); - spin_unlock_irqrestore(&devc->lock, flags); - } - - if (devc->version != 0) - if (mpu_cmd(m, 0xC5, 0) >= 0) /* Set timebase OK */ - if (mpu_cmd(m, 0xE0, 120) >= 0) /* Set tempo OK */ - devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - - - mpu401_synth_operations[m] = kmalloc(sizeof(struct synth_operations), GFP_KERNEL); - - if (mpu401_synth_operations[m] == NULL) - { - printk(KERN_ERR "mpu401: Can't allocate memory\n"); - ret = -ENOMEM; - goto out_irq; - } - if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ - { - memcpy((char *) mpu401_synth_operations[m], - (char *) &std_midi_synth, - sizeof(struct synth_operations)); - } - else - { - memcpy((char *) mpu401_synth_operations[m], - (char *) &mpu401_synth_proto, - sizeof(struct synth_operations)); - } - if (owner) - mpu401_synth_operations[m]->owner = owner; - - memcpy((char *) &mpu401_midi_operations[m], - (char *) &mpu401_midi_proto, - sizeof(struct midi_operations)); - - mpu401_midi_operations[m].converter = mpu401_synth_operations[m]; - - memcpy((char *) &mpu_synth_info[m], - (char *) &mpu_synth_info_proto, - sizeof(struct synth_info)); - - n_mpu_devs++; - - if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ - { - int ports = (devc->revision & 0x08) ? 32 : 16; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | - MPU_CAP_CLS | MPU_CAP_2PORT; - - revision_char = (devc->revision == 0x7f) ? 'M' : ' '; - sprintf(mpu_synth_info[m].name, "MQX-%d%c MIDI Interface #%d", - ports, - revision_char, - n_mpu_devs); - } - else - { - revision_char = devc->revision ? devc->revision + '@' : ' '; - if ((int) devc->revision > ('Z' - '@')) - revision_char = '+'; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - - if (hw_config->name) - sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name); - else - sprintf(mpu_synth_info[m].name, - "MPU-401 %d.%d%c MIDI #%d", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char, - n_mpu_devs); - } - - strcpy(mpu401_midi_operations[m].info.name, - mpu_synth_info[m].name); - - conf_printf(mpu_synth_info[m].name, hw_config); - - mpu401_synth_operations[m]->midi_dev = devc->devno = m; - mpu401_synth_operations[devc->devno]->info = &mpu_synth_info[devc->devno]; - - if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */ - hw_config->slots[2] = mpu_timer_init(m); - - midi_devs[m] = &mpu401_midi_operations[devc->devno]; - - if (owner) - midi_devs[m]->owner = owner; - - hw_config->slots[1] = m; - sequencer_init(); - - return 0; - -out_irq: - free_irq(devc->irq, hw_config); -out_mididev: - sound_unload_mididev(m); -out_err: - release_region(hw_config->io_base, 2); - return ret; -} - -static int reset_mpu401(struct mpu_config *devc) -{ - unsigned long flags; - int ok, timeout, n; - int timeout_limit; - - /* - * Send the RESET command. Try again if no success at the first time. - * (If the device is in the UART mode, it will not ack the reset cmd). - */ - - ok = 0; - - timeout_limit = devc->initialized ? 30000 : 100000; - devc->initialized = 1; - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) - ok = output_ready(devc); - - write_command(devc, MPU_RESET); /* - * Send MPU-401 RESET Command - */ - - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ - - for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) - { - spin_lock_irqsave(&devc->lock,flags); - if (input_avail(devc)) - if (read_data(devc) == MPU_ACK) - ok = 1; - spin_unlock_irqrestore(&devc->lock,flags); - } - - } - - devc->m_state = ST_INIT; - devc->m_ptr = 0; - devc->m_left = 0; - devc->last_status = 0; - devc->uart_mode = 0; - - return ok; -} - -static void set_uart_mode(int dev, struct mpu_config *devc, int arg) -{ - if (!arg && (devc->capabilities & MPU_CAP_INTLG)) - return; - if ((devc->uart_mode == 0) == (arg == 0)) - return; /* Already set */ - reset_mpu401(devc); /* This exits the uart mode */ - - if (arg) - { - if (mpu_cmd(dev, UART_MODE_ON, 0) < 0) - { - printk(KERN_ERR "mpu401: Can't enter UART mode\n"); - devc->uart_mode = 0; - return; - } - } - devc->uart_mode = arg; - -} - -int probe_mpu401(struct address_info *hw_config, struct resource *ports) -{ - int ok = 0; - struct mpu_config tmp_devc; - - tmp_devc.base = hw_config->io_base; - tmp_devc.irq = hw_config->irq; - tmp_devc.initialized = 0; - tmp_devc.opened = 0; - tmp_devc.osp = hw_config->osp; - - if (hw_config->always_detect) - return 1; - - if (inb(hw_config->io_base + 1) == 0xff) - { - DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base)); - return 0; /* Just bus float? */ - } - ok = reset_mpu401(&tmp_devc); - - if (!ok) - { - DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base)); - } - return ok; -} - -void unload_mpu401(struct address_info *hw_config) -{ - void *p; - int n=hw_config->slots[1]; - - if (n != -1) { - release_region(hw_config->io_base, 2); - if (hw_config->always_detect == 0 && hw_config->irq > 0) - free_irq(hw_config->irq, hw_config); - p=mpu401_synth_operations[n]; - sound_unload_mididev(n); - sound_unload_timerdev(hw_config->slots[2]); - kfree(p); - } -} - -/***************************************************** - * Timer stuff - ****************************************************/ - -static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; -static volatile int curr_tempo, curr_timebase, hw_timebase; -static int max_timebase = 8; /* 8*24=192 ppqn */ -static volatile unsigned long next_event_time; -static volatile unsigned long curr_ticks, curr_clocks; -static unsigned long prev_event_time; -static int metronome_mode; - -static unsigned long clocks2ticks(unsigned long clocks) -{ - /* - * The MPU-401 supports just a limited set of possible timebase values. - * Since the applications require more choices, the driver has to - * program the HW to do its best and to convert between the HW and - * actual timebases. - */ - return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; -} - -static void set_timebase(int midi_dev, int val) -{ - int hw_val; - - if (val < 48) - val = 48; - if (val > 1000) - val = 1000; - - hw_val = val; - hw_val = (hw_val + 12) / 24; - if (hw_val > max_timebase) - hw_val = max_timebase; - - if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) - { - printk(KERN_WARNING "mpu401: Can't set HW timebase to %d\n", hw_val * 24); - return; - } - hw_timebase = hw_val * 24; - curr_timebase = val; - -} - -static void tmr_reset(struct mpu_config *devc) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = curr_clocks = 0; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void set_timer_mode(int midi_dev) -{ - if (timer_mode & TMR_MODE_CLS) - mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ - - if (timer_mode & TMR_INTERNAL) - { - mpu_cmd(midi_dev, 0x80, 0); /* Use MIDI sync */ - } - else - { - if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) - { - mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */ - mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ - } - else if (timer_mode & TMR_MODE_FSK) - mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */ - } -} - -static void stop_metronome(int midi_dev) -{ - mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ -} - -static void setup_metronome(int midi_dev) -{ - int numerator, denominator; - int clks_per_click, num_32nds_per_beat; - int beats_per_measure; - - numerator = ((unsigned) metronome_mode >> 24) & 0xff; - denominator = ((unsigned) metronome_mode >> 16) & 0xff; - clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff; - num_32nds_per_beat = (unsigned) metronome_mode & 0xff; - beats_per_measure = (numerator * 4) >> denominator; - - if (!metronome_mode) - mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ - else - { - mpu_cmd(midi_dev, 0xE4, clks_per_click); - mpu_cmd(midi_dev, 0xE6, beats_per_measure); - mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */ - } -} - -static int mpu_start_timer(int midi_dev) -{ - struct mpu_config *devc= &dev_conf[midi_dev]; - - tmr_reset(devc); - set_timer_mode(midi_dev); - - if (tmr_running) - return TIMER_NOT_ARMED; /* Already running */ - - if (timer_mode & TMR_INTERNAL) - { - mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */ - tmr_running = 1; - return TIMER_NOT_ARMED; - } - else - { - mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */ - mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */ - mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */ - mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ - } - return TIMER_ARMED; -} - -static int mpu_timer_open(int dev, int mode) -{ - int midi_dev = sound_timer_devs[dev]->devlink; - struct mpu_config *devc= &dev_conf[midi_dev]; - - if (timer_open) - return -EBUSY; - - tmr_reset(devc); - curr_tempo = 50; - mpu_cmd(midi_dev, 0xE0, 50); - curr_timebase = hw_timebase = 120; - set_timebase(midi_dev, 120); - timer_open = 1; - metronome_mode = 0; - set_timer_mode(midi_dev); - - mpu_cmd(midi_dev, 0xe7, 0x04); /* Send all clocks to host */ - mpu_cmd(midi_dev, 0x95, 0); /* Enable clock to host */ - - return 0; -} - -static void mpu_timer_close(int dev) -{ - int midi_dev = sound_timer_devs[dev]->devlink; - - timer_open = tmr_running = 0; - mpu_cmd(midi_dev, 0x15, 0); /* Stop all */ - mpu_cmd(midi_dev, 0x94, 0); /* Disable clock to host */ - mpu_cmd(midi_dev, 0x8c, 0); /* Disable measure end messages to host */ - stop_metronome(midi_dev); -} - -static int mpu_timer_event(int dev, unsigned char *event) -{ - unsigned char command = event[1]; - unsigned long parm = *(unsigned int *) &event[4]; - int midi_dev = sound_timer_devs[dev]->devlink; - - switch (command) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - if (tmr_running) - break; - return mpu_start_timer(midi_dev); - - case TMR_STOP: - mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome(midi_dev); - tmr_running = 0; - break; - - case TMR_CONTINUE: - if (tmr_running) - break; - mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ - setup_metronome(midi_dev); - tmr_running = 1; - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - if (mpu_cmd(midi_dev, 0xE0, parm) < 0) - printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) parm); - curr_tempo = parm; - } - break; - - case TMR_ECHO: - seq_copy_to_input(event, 8); - break; - - case TMR_TIMESIG: - if (metronome_mode) /* Metronome enabled */ - { - metronome_mode = parm; - setup_metronome(midi_dev); - } - break; - - default:; - } - return TIMER_NOT_ARMED; -} - -static unsigned long mpu_timer_get_time(int dev) -{ - if (!timer_open) - return 0; - - return curr_ticks; -} - -static int mpu_timer_ioctl(int dev, unsigned int command, void __user *arg) -{ - int midi_dev = sound_timer_devs[dev]->devlink; - int __user *p = (int __user *)arg; - - switch (command) - { - case SNDCTL_TMR_SOURCE: - { - int parm; - - if (get_user(parm, p)) - return -EFAULT; - parm &= timer_caps; - - if (parm != 0) - { - timer_mode = parm; - - if (timer_mode & TMR_MODE_CLS) - mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ - } - if (put_user(timer_mode, p)) - return -EFAULT; - return timer_mode; - } - break; - - case SNDCTL_TMR_START: - mpu_start_timer(midi_dev); - return 0; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome(midi_dev); - return 0; - - case SNDCTL_TMR_CONTINUE: - if (tmr_running) - return 0; - tmr_running = 1; - mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ - return 0; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - if (get_user(val, p)) - return -EFAULT; - if (val) - set_timebase(midi_dev, val); - if (put_user(curr_timebase, p)) - return -EFAULT; - return curr_timebase; - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - int ret; - - if (get_user(val, p)) - return -EFAULT; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) - { - printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) val); - return ret; - } - curr_tempo = val; - } - if (put_user(curr_tempo, p)) - return -EFAULT; - return curr_tempo; - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - if (get_user(val, p)) - return -EFAULT; - - if (val != 0) /* Can't change */ - return -EINVAL; - val = ((curr_tempo * curr_timebase) + 30)/60; - if (put_user(val, p)) - return -EFAULT; - return val; - } - break; - - case SNDCTL_SEQ_GETTIME: - if (put_user(curr_ticks, p)) - return -EFAULT; - return curr_ticks; - - case SNDCTL_TMR_METRONOME: - if (get_user(metronome_mode, p)) - return -EFAULT; - setup_metronome(midi_dev); - return 0; - - default:; - } - return -EINVAL; -} - -static void mpu_timer_arm(int dev, long time) -{ - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; - next_event_time = prev_event_time = time; - return; -} - -static struct sound_timer_operations mpu_timer = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 Timer", 0}, - .priority = 10, /* Priority */ - .devlink = 0, /* Local device link */ - .open = mpu_timer_open, - .close = mpu_timer_close, - .event = mpu_timer_event, - .get_time = mpu_timer_get_time, - .ioctl = mpu_timer_ioctl, - .arm_timer = mpu_timer_arm -}; - -static void mpu_timer_interrupt(void) -{ - if (!timer_open) - return; - - if (!tmr_running) - return; - - curr_clocks++; - curr_ticks = clocks2ticks(curr_clocks); - - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } -} - -static void timer_ext_event(struct mpu_config *devc, int event, int parm) -{ - int midi_dev = devc->devno; - - if (!devc->timer_flag) - return; - - switch (event) - { - case TMR_CLOCK: - printk("<MIDI clk>"); - break; - - case TMR_START: - printk("Ext MIDI start\n"); - if (!tmr_running) - { - if (timer_mode & TMR_EXTERNAL) - { - tmr_running = 1; - setup_metronome(midi_dev); - next_event_time = 0; - STORE(SEQ_START_TIMER()); - } - } - break; - - case TMR_STOP: - printk("Ext MIDI stop\n"); - if (timer_mode & TMR_EXTERNAL) - { - tmr_running = 0; - stop_metronome(midi_dev); - STORE(SEQ_STOP_TIMER()); - } - break; - - case TMR_CONTINUE: - printk("Ext MIDI continue\n"); - if (timer_mode & TMR_EXTERNAL) - { - tmr_running = 1; - setup_metronome(midi_dev); - STORE(SEQ_CONTINUE_TIMER()); - } - break; - - case TMR_SPP: - printk("Songpos: %d\n", parm); - if (timer_mode & TMR_EXTERNAL) - { - STORE(SEQ_SONGPOS(parm)); - } - break; - } -} - -static int mpu_timer_init(int midi_dev) -{ - struct mpu_config *devc; - int n; - - devc = &dev_conf[midi_dev]; - - if (timer_initialized) - return -1; /* There is already a similar timer */ - - timer_initialized = 1; - - mpu_timer.devlink = midi_dev; - dev_conf[midi_dev].timer_flag = 1; - - n = sound_alloc_timerdev(); - if (n == -1) - n = 0; - sound_timer_devs[n] = &mpu_timer; - - if (devc->version < 0x20) /* Original MPU-401 */ - timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI; - else - { - /* - * The version number 2.0 is used (at least) by the - * MusicQuest cards and the Roland Super-MPU. - * - * MusicQuest has given a special meaning to the bits of the - * revision number. The Super-MPU returns 0. - */ - - if (devc->revision) - timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; - - if (devc->revision & 0x02) - timer_caps |= TMR_MODE_CLS; - - - if (devc->revision & 0x40) - max_timebase = 10; /* Has the 216 and 240 ppqn modes */ - } - - timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; - return n; - -} - -EXPORT_SYMBOL(probe_mpu401); -EXPORT_SYMBOL(attach_mpu401); -EXPORT_SYMBOL(unload_mpu401); - -static struct address_info cfg; - -static int io = -1; -static int irq = -1; - -module_param_hw(irq, int, irq, 0); -module_param_hw(io, int, ioport, 0); - -static int __init init_mpu401(void) -{ - int ret; - /* Can be loaded either for module use or to provide functions - to others */ - if (io != -1 && irq != -1) { - struct resource *ports; - cfg.irq = irq; - cfg.io_base = io; - ports = request_region(io, 2, "mpu401"); - if (!ports) - return -EBUSY; - if (probe_mpu401(&cfg, ports) == 0) { - release_region(io, 2); - return -ENODEV; - } - if ((ret = attach_mpu401(&cfg, THIS_MODULE))) - return ret; - } - - return 0; -} - -static void __exit cleanup_mpu401(void) -{ - if (io != -1 && irq != -1) { - /* Check for use by, for example, sscape driver */ - unload_mpu401(&cfg); - } -} - -module_init(init_mpu401); -module_exit(cleanup_mpu401); - -#ifndef MODULE -static int __init setup_mpu401(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} - -__setup("mpu401=", setup_mpu401); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h deleted file mode 100644 index 6beb8c2ae405..000000000000 --- a/sound/oss/mpu401.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* From uart401.c */ -int probe_uart401 (struct address_info *hw_config, struct module *owner); -void unload_uart401 (struct address_info *hw_config); - -irqreturn_t uart401intr (int irq, void *dev_id); - -/* From mpu401.c */ -int probe_mpu401(struct address_info *hw_config, struct resource *ports); -int attach_mpu401(struct address_info * hw_config, struct module *owner); -void unload_mpu401(struct address_info *hw_info); diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c deleted file mode 100644 index b63010ad22f1..000000000000 --- a/sound/oss/msnd.c +++ /dev/null @@ -1,413 +0,0 @@ -/********************************************************************* - * - * msnd.c - Driver Base - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Copyright (C) 1998 Andrew Veliath - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/vmalloc.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/interrupt.h> - -#include <asm/io.h> -#include <linux/uaccess.h> -#include <linux/spinlock.h> -#include <asm/irq.h> -#include "msnd.h" - -#define LOGNAME "msnd" - -#define MSND_MAX_DEVS 4 - -static multisound_dev_t *devs[MSND_MAX_DEVS]; -static int num_devs; - -int msnd_register(multisound_dev_t *dev) -{ - int i; - - for (i = 0; i < MSND_MAX_DEVS; ++i) - if (devs[i] == NULL) - break; - - if (i == MSND_MAX_DEVS) - return -ENOMEM; - - devs[i] = dev; - ++num_devs; - return 0; -} - -void msnd_unregister(multisound_dev_t *dev) -{ - int i; - - for (i = 0; i < MSND_MAX_DEVS; ++i) - if (devs[i] == dev) - break; - - if (i == MSND_MAX_DEVS) { - printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n"); - return; - } - - devs[i] = NULL; - --num_devs; -} - -void msnd_init_queue(void __iomem *base, int start, int size) -{ - writew(PCTODSP_BASED(start), base + JQS_wStart); - writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); - writew(0, base + JQS_wHead); - writew(0, base + JQS_wTail); -} - -void msnd_fifo_init(msnd_fifo *f) -{ - f->data = NULL; -} - -void msnd_fifo_free(msnd_fifo *f) -{ - vfree(f->data); - f->data = NULL; -} - -int msnd_fifo_alloc(msnd_fifo *f, size_t n) -{ - msnd_fifo_free(f); - f->data = vmalloc(n); - f->n = n; - f->tail = 0; - f->head = 0; - f->len = 0; - - if (!f->data) - return -ENOMEM; - - return 0; -} - -void msnd_fifo_make_empty(msnd_fifo *f) -{ - f->len = f->tail = f->head = 0; -} - -int msnd_fifo_write_io(msnd_fifo *f, char __iomem *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len != f->n)) { - - int nwritten; - - if (f->head <= f->tail) { - nwritten = len - count; - if (nwritten > f->n - f->tail) - nwritten = f->n - f->tail; - } - else { - nwritten = f->head - f->tail; - if (nwritten > len - count) - nwritten = len - count; - } - - memcpy_fromio(f->data + f->tail, buf, nwritten); - - count += nwritten; - buf += nwritten; - f->len += nwritten; - f->tail += nwritten; - f->tail %= f->n; - } - - return count; -} - -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len != f->n)) { - - int nwritten; - - if (f->head <= f->tail) { - nwritten = len - count; - if (nwritten > f->n - f->tail) - nwritten = f->n - f->tail; - } - else { - nwritten = f->head - f->tail; - if (nwritten > len - count) - nwritten = len - count; - } - - memcpy(f->data + f->tail, buf, nwritten); - - count += nwritten; - buf += nwritten; - f->len += nwritten; - f->tail += nwritten; - f->tail %= f->n; - } - - return count; -} - -int msnd_fifo_read_io(msnd_fifo *f, char __iomem *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len > 0)) { - - int nread; - - if (f->tail <= f->head) { - nread = len - count; - if (nread > f->n - f->head) - nread = f->n - f->head; - } - else { - nread = f->tail - f->head; - if (nread > len - count) - nread = len - count; - } - - memcpy_toio(buf, f->data + f->head, nread); - - count += nread; - buf += nread; - f->len -= nread; - f->head += nread; - f->head %= f->n; - } - - return count; -} - -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len) -{ - int count = 0; - - while ((count < len) && (f->len > 0)) { - - int nread; - - if (f->tail <= f->head) { - nread = len - count; - if (nread > f->n - f->head) - nread = f->n - f->head; - } - else { - nread = f->tail - f->head; - if (nread > len - count) - nread = len - count; - } - - memcpy(buf, f->data + f->head, nread); - - count += nread; - buf += nread; - f->len -= nread; - f->head += nread; - f->head %= f->n; - } - - return count; -} - -static int msnd_wait_TXDE(multisound_dev_t *dev) -{ - register unsigned int io = dev->io; - register int timeout = 1000; - - while(timeout-- > 0) - if (msnd_inb(io + HP_ISR) & HPISR_TXDE) - return 0; - - return -EIO; -} - -static int msnd_wait_HC0(multisound_dev_t *dev) -{ - register unsigned int io = dev->io; - register int timeout = 1000; - - while(timeout-- > 0) - if (!(msnd_inb(io + HP_CVR) & HPCVR_HC)) - return 0; - - return -EIO; -} - -int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (msnd_wait_HC0(dev) == 0) { - msnd_outb(cmd, dev->io + HP_CVR); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n"); - - return -EIO; -} - -int msnd_send_word(multisound_dev_t *dev, unsigned char high, - unsigned char mid, unsigned char low) -{ - register unsigned int io = dev->io; - - if (msnd_wait_TXDE(dev) == 0) { - msnd_outb(high, io + HP_TXH); - msnd_outb(mid, io + HP_TXM); - msnd_outb(low, io + HP_TXL); - return 0; - } - - printk(KERN_DEBUG LOGNAME ": Send host word timeout\n"); - - return -EIO; -} - -int msnd_upload_host(multisound_dev_t *dev, char *bin, int len) -{ - int i; - - if (len % 3 != 0) { - printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n"); - return -EINVAL; - } - - for (i = 0; i < len; i += 3) - if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0) - return -EIO; - - msnd_inb(dev->io + HP_RXL); - msnd_inb(dev->io + HP_CVR); - - return 0; -} - -int msnd_enable_irq(multisound_dev_t *dev) -{ - unsigned long flags; - - if (dev->irq_ref++) - return 0; - - printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n"); - - spin_lock_irqsave(&dev->lock, flags); - if (msnd_wait_TXDE(dev) == 0) { - msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); - if (dev->type == msndClassic) - msnd_outb(dev->irqid, dev->io + HP_IRQM); - msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR); - msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR); - enable_irq(dev->irq); - msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n"); - - return -EIO; -} - -int msnd_disable_irq(multisound_dev_t *dev) -{ - unsigned long flags; - - if (--dev->irq_ref > 0) - return 0; - - if (dev->irq_ref < 0) - printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); - - printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n"); - - spin_lock_irqsave(&dev->lock, flags); - if (msnd_wait_TXDE(dev) == 0) { - msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); - if (dev->type == msndClassic) - msnd_outb(HPIRQ_NONE, dev->io + HP_IRQM); - disable_irq(dev->irq); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n"); - - return -EIO; -} - -#ifndef LINUX20 -EXPORT_SYMBOL(msnd_register); -EXPORT_SYMBOL(msnd_unregister); - -EXPORT_SYMBOL(msnd_init_queue); - -EXPORT_SYMBOL(msnd_fifo_init); -EXPORT_SYMBOL(msnd_fifo_free); -EXPORT_SYMBOL(msnd_fifo_alloc); -EXPORT_SYMBOL(msnd_fifo_make_empty); -EXPORT_SYMBOL(msnd_fifo_write_io); -EXPORT_SYMBOL(msnd_fifo_read_io); -EXPORT_SYMBOL(msnd_fifo_write); -EXPORT_SYMBOL(msnd_fifo_read); - -EXPORT_SYMBOL(msnd_send_dsp_cmd); -EXPORT_SYMBOL(msnd_send_word); -EXPORT_SYMBOL(msnd_upload_host); - -EXPORT_SYMBOL(msnd_enable_irq); -EXPORT_SYMBOL(msnd_disable_irq); -#endif - -#ifdef MODULE -MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>"); -MODULE_DESCRIPTION ("Turtle Beach MultiSound Driver Base"); -MODULE_LICENSE("GPL"); - - -int init_module(void) -{ - return 0; -} - -void cleanup_module(void) -{ -} -#endif diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h deleted file mode 100644 index c8be47ec2b7e..000000000000 --- a/sound/oss/msnd.h +++ /dev/null @@ -1,278 +0,0 @@ -/********************************************************************* - * - * msnd.h - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Some parts of this header file were derived from the Turtle Beach - * MultiSound Driver Development Kit. - * - * Copyright (C) 1998 Andrew Veliath - * Copyright (C) 1993 Turtle Beach Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ********************************************************************/ -#ifndef __MSND_H -#define __MSND_H - -#define VERSION "0.8.3.1" - -#define DEFSAMPLERATE DSP_DEFAULT_SPEED -#define DEFSAMPLESIZE AFMT_U8 -#define DEFCHANNELS 1 - -#define DEFFIFOSIZE 128 - -#define SNDCARD_MSND 38 - -#define SRAM_BANK_SIZE 0x8000 -#define SRAM_CNTL_START 0x7F00 - -#define DSP_BASE_ADDR 0x4000 -#define DSP_BANK_BASE 0x4000 - -#define HP_ICR 0x00 -#define HP_CVR 0x01 -#define HP_ISR 0x02 -#define HP_IVR 0x03 -#define HP_NU 0x04 -#define HP_INFO 0x04 -#define HP_TXH 0x05 -#define HP_RXH 0x05 -#define HP_TXM 0x06 -#define HP_RXM 0x06 -#define HP_TXL 0x07 -#define HP_RXL 0x07 - -#define HP_ICR_DEF 0x00 -#define HP_CVR_DEF 0x12 -#define HP_ISR_DEF 0x06 -#define HP_IVR_DEF 0x0f -#define HP_NU_DEF 0x00 - -#define HP_IRQM 0x09 - -#define HPR_BLRC 0x08 -#define HPR_SPR1 0x09 -#define HPR_SPR2 0x0A -#define HPR_TCL0 0x0B -#define HPR_TCL1 0x0C -#define HPR_TCL2 0x0D -#define HPR_TCL3 0x0E -#define HPR_TCL4 0x0F - -#define HPICR_INIT 0x80 -#define HPICR_HM1 0x40 -#define HPICR_HM0 0x20 -#define HPICR_HF1 0x10 -#define HPICR_HF0 0x08 -#define HPICR_TREQ 0x02 -#define HPICR_RREQ 0x01 - -#define HPCVR_HC 0x80 - -#define HPISR_HREQ 0x80 -#define HPISR_DMA 0x40 -#define HPISR_HF3 0x10 -#define HPISR_HF2 0x08 -#define HPISR_TRDY 0x04 -#define HPISR_TXDE 0x02 -#define HPISR_RXDF 0x01 - -#define HPIO_290 0 -#define HPIO_260 1 -#define HPIO_250 2 -#define HPIO_240 3 -#define HPIO_230 4 -#define HPIO_220 5 -#define HPIO_210 6 -#define HPIO_3E0 7 - -#define HPMEM_NONE 0 -#define HPMEM_B000 1 -#define HPMEM_C800 2 -#define HPMEM_D000 3 -#define HPMEM_D400 4 -#define HPMEM_D800 5 -#define HPMEM_E000 6 -#define HPMEM_E800 7 - -#define HPIRQ_NONE 0 -#define HPIRQ_5 1 -#define HPIRQ_7 2 -#define HPIRQ_9 3 -#define HPIRQ_10 4 -#define HPIRQ_11 5 -#define HPIRQ_12 6 -#define HPIRQ_15 7 - -#define HIMT_PLAY_DONE 0x00 -#define HIMT_RECORD_DONE 0x01 -#define HIMT_MIDI_EOS 0x02 -#define HIMT_MIDI_OUT 0x03 - -#define HIMT_MIDI_IN_UCHAR 0x0E -#define HIMT_DSP 0x0F - -#define HDEX_BASE 0x92 -#define HDEX_PLAY_START (0 + HDEX_BASE) -#define HDEX_PLAY_STOP (1 + HDEX_BASE) -#define HDEX_PLAY_PAUSE (2 + HDEX_BASE) -#define HDEX_PLAY_RESUME (3 + HDEX_BASE) -#define HDEX_RECORD_START (4 + HDEX_BASE) -#define HDEX_RECORD_STOP (5 + HDEX_BASE) -#define HDEX_MIDI_IN_START (6 + HDEX_BASE) -#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE) -#define HDEX_MIDI_OUT_START (8 + HDEX_BASE) -#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE) -#define HDEX_AUX_REQ (10 + HDEX_BASE) - -#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF)) -#define LOWORD(l) ((WORD)(DWORD)(l)) -#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) -#define LOBYTE(w) ((BYTE)(w)) -#define MAKELONG(low,hi) ((long)(((WORD)(low))|(((DWORD)((WORD)(hi)))<<16))) -#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8))) - -#define PCTODSP_OFFSET(w) (USHORT)((w)/2) -#define PCTODSP_BASED(w) (USHORT)(((w)/2) + DSP_BASE_ADDR) -#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2) - -#ifdef SLOWIO -#define msnd_outb outb_p -#define msnd_inb inb_p -#else -#define msnd_outb outb -#define msnd_inb inb -#endif - -/* JobQueueStruct */ -#define JQS_wStart 0x00 -#define JQS_wSize 0x02 -#define JQS_wHead 0x04 -#define JQS_wTail 0x06 -#define JQS__size 0x08 - -/* DAQueueDataStruct */ -#define DAQDS_wStart 0x00 -#define DAQDS_wSize 0x02 -#define DAQDS_wFormat 0x04 -#define DAQDS_wSampleSize 0x06 -#define DAQDS_wChannels 0x08 -#define DAQDS_wSampleRate 0x0A -#define DAQDS_wIntMsg 0x0C -#define DAQDS_wFlags 0x0E -#define DAQDS__size 0x10 - -typedef u8 BYTE; -typedef u16 USHORT; -typedef u16 WORD; -typedef u32 DWORD; -typedef void __iomem * LPDAQD; - -/* Generic FIFO */ -typedef struct { - size_t n, len; - char *data; - int head, tail; -} msnd_fifo; - -typedef struct multisound_dev { - /* Linux device info */ - char *name; - int dsp_minor, mixer_minor; - int ext_midi_dev, hdr_midi_dev; - - /* Hardware resources */ - int io, numio; - int memid, irqid; - int irq, irq_ref; - unsigned char info; - void __iomem *base; - - /* Motorola 56k DSP SMA */ - void __iomem *SMA; - void __iomem *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ; - void __iomem *pwDSPQData, *pwMIDQData, *pwMODQData; - int dspq_data_buff, dspq_buff_size; - - /* State variables */ - enum { msndClassic, msndPinnacle } type; - fmode_t mode; - unsigned long flags; -#define F_RESETTING 0 -#define F_HAVEDIGITAL 1 -#define F_AUDIO_WRITE_INUSE 2 -#define F_WRITING 3 -#define F_WRITEBLOCK 4 -#define F_WRITEFLUSH 5 -#define F_AUDIO_READ_INUSE 6 -#define F_READING 7 -#define F_READBLOCK 8 -#define F_EXT_MIDI_INUSE 9 -#define F_HDR_MIDI_INUSE 10 -#define F_DISABLE_WRITE_NDELAY 11 - wait_queue_head_t writeblock; - wait_queue_head_t readblock; - wait_queue_head_t writeflush; - spinlock_t lock; - int nresets; - unsigned long recsrc; - int left_levels[32]; - int right_levels[32]; - int mixer_mod_count; - int calibrate_signal; - int play_sample_size, play_sample_rate, play_channels; - int play_ndelay; - int rec_sample_size, rec_sample_rate, rec_channels; - int rec_ndelay; - BYTE bCurrentMidiPatch; - - /* Digital audio FIFOs */ - msnd_fifo DAPF, DARF; - int fifosize; - int last_playbank, last_recbank; - - /* MIDI in callback */ - void (*midi_in_interrupt)(struct multisound_dev *); -} multisound_dev_t; - -#ifndef mdelay -# define mdelay(a) udelay((a) * 1000) -#endif - -int msnd_register(multisound_dev_t *dev); -void msnd_unregister(multisound_dev_t *dev); - -void msnd_init_queue(void __iomem *, int start, int size); - -void msnd_fifo_init(msnd_fifo *f); -void msnd_fifo_free(msnd_fifo *f); -int msnd_fifo_alloc(msnd_fifo *f, size_t n); -void msnd_fifo_make_empty(msnd_fifo *f); -int msnd_fifo_write_io(msnd_fifo *f, char __iomem *buf, size_t len); -int msnd_fifo_read_io(msnd_fifo *f, char __iomem *buf, size_t len); -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len); -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len); - -int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd); -int msnd_send_word(multisound_dev_t *dev, unsigned char high, - unsigned char mid, unsigned char low); -int msnd_upload_host(multisound_dev_t *dev, char *bin, int len); -int msnd_enable_irq(multisound_dev_t *dev); -int msnd_disable_irq(multisound_dev_t *dev); - -#endif /* __MSND_H */ diff --git a/sound/oss/msnd_classic.c b/sound/oss/msnd_classic.c deleted file mode 100644 index 3b23a096fa4e..000000000000 --- a/sound/oss/msnd_classic.c +++ /dev/null @@ -1,3 +0,0 @@ -/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */ -#define MSND_CLASSIC -#include "msnd_pinnacle.c" diff --git a/sound/oss/msnd_classic.h b/sound/oss/msnd_classic.h deleted file mode 100644 index 1a17dde2f650..000000000000 --- a/sound/oss/msnd_classic.h +++ /dev/null @@ -1,185 +0,0 @@ -/********************************************************************* - * - * msnd_classic.h - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Some parts of this header file were derived from the Turtle Beach - * MultiSound Driver Development Kit. - * - * Copyright (C) 1998 Andrew Veliath - * Copyright (C) 1993 Turtle Beach Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ********************************************************************/ -#ifndef __MSND_CLASSIC_H -#define __MSND_CLASSIC_H - - -#define DSP_NUMIO 0x10 - -#define HP_MEMM 0x08 - -#define HP_BITM 0x0E -#define HP_WAIT 0x0D -#define HP_DSPR 0x0A -#define HP_PROR 0x0B -#define HP_BLKS 0x0C - -#define HPPRORESET_OFF 0 -#define HPPRORESET_ON 1 - -#define HPDSPRESET_OFF 0 -#define HPDSPRESET_ON 1 - -#define HPBLKSEL_0 0 -#define HPBLKSEL_1 1 - -#define HPWAITSTATE_0 0 -#define HPWAITSTATE_1 1 - -#define HPBITMODE_16 0 -#define HPBITMODE_8 1 - -#define HIDSP_INT_PLAY_UNDER 0x00 -#define HIDSP_INT_RECORD_OVER 0x01 -#define HIDSP_INPUT_CLIPPING 0x02 -#define HIDSP_MIDI_IN_OVER 0x10 -#define HIDSP_MIDI_OVERRUN_ERR 0x13 - -#define HDEXAR_CLEAR_PEAKS 1 -#define HDEXAR_IN_SET_POTS 2 -#define HDEXAR_AUX_SET_POTS 3 -#define HDEXAR_CAL_A_TO_D 4 -#define HDEXAR_RD_EXT_DSP_BITS 5 - -#define TIME_PRO_RESET_DONE 0x028A -#define TIME_PRO_SYSEX 0x0040 -#define TIME_PRO_RESET 0x0032 - -#define AGND 0x01 -#define SIGNAL 0x02 - -#define EXT_DSP_BIT_DCAL 0x0001 -#define EXT_DSP_BIT_MIDI_CON 0x0002 - -#define BUFFSIZE 0x8000 -#define HOSTQ_SIZE 0x40 - -#define SRAM_CNTL_START 0x7F00 -#define SMA_STRUCT_START 0x7F40 - -#define DAP_BUFF_SIZE 0x2400 -#define DAR_BUFF_SIZE 0x2000 - -#define DAPQ_STRUCT_SIZE 0x10 -#define DARQ_STRUCT_SIZE 0x10 -#define DAPQ_BUFF_SIZE (3 * 0x10) -#define DARQ_BUFF_SIZE (3 * 0x10) -#define MODQ_BUFF_SIZE 0x400 -#define MIDQ_BUFF_SIZE 0x200 -#define DSPQ_BUFF_SIZE 0x40 - -#define DAPQ_DATA_BUFF 0x6C00 -#define DARQ_DATA_BUFF 0x6C30 -#define MODQ_DATA_BUFF 0x6C60 -#define MIDQ_DATA_BUFF 0x7060 -#define DSPQ_DATA_BUFF 0x7260 - -#define DAPQ_OFFSET SRAM_CNTL_START -#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) -#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) -#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) -#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) - -#define MOP_SYNTH 0x10 -#define MOP_EXTOUT 0x32 -#define MOP_EXTTHRU 0x02 -#define MOP_OUTMASK 0x01 - -#define MIP_EXTIN 0x01 -#define MIP_SYNTH 0x00 -#define MIP_INMASK 0x32 - -/* Classic SMA Common Data */ -#define SMA_wCurrPlayBytes 0x0000 -#define SMA_wCurrRecordBytes 0x0002 -#define SMA_wCurrPlayVolLeft 0x0004 -#define SMA_wCurrPlayVolRight 0x0006 -#define SMA_wCurrInVolLeft 0x0008 -#define SMA_wCurrInVolRight 0x000a -#define SMA_wUser_3 0x000c -#define SMA_wUser_4 0x000e -#define SMA_dwUser_5 0x0010 -#define SMA_dwUser_6 0x0014 -#define SMA_wUser_7 0x0018 -#define SMA_wReserved_A 0x001a -#define SMA_wReserved_B 0x001c -#define SMA_wReserved_C 0x001e -#define SMA_wReserved_D 0x0020 -#define SMA_wReserved_E 0x0022 -#define SMA_wReserved_F 0x0024 -#define SMA_wReserved_G 0x0026 -#define SMA_wReserved_H 0x0028 -#define SMA_wCurrDSPStatusFlags 0x002a -#define SMA_wCurrHostStatusFlags 0x002c -#define SMA_wCurrInputTagBits 0x002e -#define SMA_wCurrLeftPeak 0x0030 -#define SMA_wCurrRightPeak 0x0032 -#define SMA_wExtDSPbits 0x0034 -#define SMA_bExtHostbits 0x0036 -#define SMA_bBoardLevel 0x0037 -#define SMA_bInPotPosRight 0x0038 -#define SMA_bInPotPosLeft 0x0039 -#define SMA_bAuxPotPosRight 0x003a -#define SMA_bAuxPotPosLeft 0x003b -#define SMA_wCurrMastVolLeft 0x003c -#define SMA_wCurrMastVolRight 0x003e -#define SMA_bUser_12 0x0040 -#define SMA_bUser_13 0x0041 -#define SMA_wUser_14 0x0042 -#define SMA_wUser_15 0x0044 -#define SMA_wCalFreqAtoD 0x0046 -#define SMA_wUser_16 0x0048 -#define SMA_wUser_17 0x004a -#define SMA__size 0x004c - -#ifdef HAVE_DSPCODEH -# include "msndperm.c" -# include "msndinit.c" -# define PERMCODE msndperm -# define INITCODE msndinit -# define PERMCODESIZE sizeof(msndperm) -# define INITCODESIZE sizeof(msndinit) -#else -# ifndef CONFIG_MSNDCLAS_INIT_FILE -# define CONFIG_MSNDCLAS_INIT_FILE \ - "/etc/sound/msndinit.bin" -# endif -# ifndef CONFIG_MSNDCLAS_PERM_FILE -# define CONFIG_MSNDCLAS_PERM_FILE \ - "/etc/sound/msndperm.bin" -# endif -# define PERMCODEFILE CONFIG_MSNDCLAS_PERM_FILE -# define INITCODEFILE CONFIG_MSNDCLAS_INIT_FILE -# define PERMCODE dspini -# define INITCODE permini -# define PERMCODESIZE sizeof_dspini -# define INITCODESIZE sizeof_permini -#endif -#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)" - -#endif /* __MSND_CLASSIC_H */ diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c deleted file mode 100644 index d2abc2cf3213..000000000000 --- a/sound/oss/msnd_pinnacle.c +++ /dev/null @@ -1,1941 +0,0 @@ -/********************************************************************* - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * Linux 2.0/2.2 Version - * - * msnd_pinnacle.c / msnd_classic.c - * - * -- If MSND_CLASSIC is defined: - * - * -> driver for Turtle Beach Classic/Monterey/Tahiti - * - * -- Else - * - * -> driver for Turtle Beach Pinnacle/Fiji - * - * Copyright (C) 1998 Andrew Veliath - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * 12-3-2000 Modified IO port validation Steve Sycamore - * - ********************************************************************/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/gfp.h> -#include <linux/sched/signal.h> - -#include <asm/irq.h> -#include <asm/io.h> -#include "sound_config.h" -#include "sound_firmware.h" -#ifdef MSND_CLASSIC -# ifndef __alpha__ -# define SLOWIO -# endif -#endif -#include "msnd.h" -#ifdef MSND_CLASSIC -# ifdef CONFIG_MSNDCLAS_HAVE_BOOT -# define HAVE_DSPCODEH -# endif -# include "msnd_classic.h" -# define LOGNAME "msnd_classic" -#else -# ifdef CONFIG_MSNDPIN_HAVE_BOOT -# define HAVE_DSPCODEH -# endif -# include "msnd_pinnacle.h" -# define LOGNAME "msnd_pinnacle" -#endif - -#ifndef CONFIG_MSND_WRITE_NDELAY -# define CONFIG_MSND_WRITE_NDELAY 1 -#endif - -#define get_play_delay_jiffies(size) ((size) * HZ * \ - dev.play_sample_size / 8 / \ - dev.play_sample_rate / \ - dev.play_channels) - -#define get_rec_delay_jiffies(size) ((size) * HZ * \ - dev.rec_sample_size / 8 / \ - dev.rec_sample_rate / \ - dev.rec_channels) - -static DEFINE_MUTEX(msnd_pinnacle_mutex); -static multisound_dev_t dev; - -#ifndef HAVE_DSPCODEH -static char *dspini, *permini; -static int sizeof_dspini, sizeof_permini; -#endif - -static int dsp_full_reset(void); -static void dsp_write_flush(void); - -static __inline__ int chk_send_dsp_cmd(multisound_dev_t *dev, register BYTE cmd) -{ - if (msnd_send_dsp_cmd(dev, cmd) == 0) - return 0; - dsp_full_reset(); - return msnd_send_dsp_cmd(dev, cmd); -} - -static void reset_play_queue(void) -{ - int n; - LPDAQD lpDAQ; - - dev.last_playbank = -1; - writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead); - writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail); - - for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { - writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart); - writew(0, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.play_channels, lpDAQ + DAQDS_wChannels); - writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n, lpDAQ + DAQDS_wFlags); - } -} - -static void reset_record_queue(void) -{ - int n; - LPDAQD lpDAQ; - unsigned long flags; - - dev.last_recbank = 2; - writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead); - writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail); - - /* Critical section: bank 1 access */ - spin_lock_irqsave(&dev.lock, flags); - msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS); - memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - spin_unlock_irqrestore(&dev.lock, flags); - - for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { - writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart); - writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.rec_channels, lpDAQ + DAQDS_wChannels); - writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n, lpDAQ + DAQDS_wFlags); - } -} - -static void reset_queues(void) -{ - if (dev.mode & FMODE_WRITE) { - msnd_fifo_make_empty(&dev.DAPF); - reset_play_queue(); - } - if (dev.mode & FMODE_READ) { - msnd_fifo_make_empty(&dev.DARF); - reset_record_queue(); - } -} - -static int dsp_set_format(struct file *file, int val) -{ - int data, i; - LPDAQD lpDAQ, lpDARQ; - - lpDAQ = dev.base + DAPQ_DATA_BUFF; - lpDARQ = dev.base + DARQ_DATA_BUFF; - - switch (val) { - case AFMT_U8: - case AFMT_S16_LE: - data = val; - break; - default: - data = DEFSAMPLESIZE; - break; - } - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - if (file->f_mode & FMODE_WRITE) - writew(data, lpDAQ + DAQDS_wSampleSize); - if (file->f_mode & FMODE_READ) - writew(data, lpDARQ + DAQDS_wSampleSize); - } - if (file->f_mode & FMODE_WRITE) - dev.play_sample_size = data; - if (file->f_mode & FMODE_READ) - dev.rec_sample_size = data; - - return data; -} - -static int dsp_get_frag_size(void) -{ - int size; - size = dev.fifosize / 4; - if (size > 32 * 1024) - size = 32 * 1024; - return size; -} - -static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int val, i, data, tmp; - LPDAQD lpDAQ, lpDARQ; - audio_buf_info abinfo; - unsigned long flags; - int __user *p = (int __user *)arg; - - lpDAQ = dev.base + DAPQ_DATA_BUFF; - lpDARQ = dev.base + DARQ_DATA_BUFF; - - switch (cmd) { - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - case SNDCTL_DSP_SETDUPLEX: - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETIPTR: - case SNDCTL_DSP_GETOPTR: - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - return -EINVAL; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&dev.lock, flags); - abinfo.fragsize = dsp_get_frag_size(); - abinfo.bytes = dev.DAPF.n - dev.DAPF.len; - abinfo.fragstotal = dev.DAPF.n / abinfo.fragsize; - abinfo.fragments = abinfo.bytes / abinfo.fragsize; - spin_unlock_irqrestore(&dev.lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&dev.lock, flags); - abinfo.fragsize = dsp_get_frag_size(); - abinfo.bytes = dev.DARF.n - dev.DARF.len; - abinfo.fragstotal = dev.DARF.n / abinfo.fragsize; - abinfo.fragments = abinfo.bytes / abinfo.fragsize; - spin_unlock_irqrestore(&dev.lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_RESET: - dev.nresets = 0; - reset_queues(); - return 0; - - case SNDCTL_DSP_SYNC: - dsp_write_flush(); - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - tmp = dsp_get_frag_size(); - if (put_user(tmp, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETFMTS: - val = AFMT_S16_LE | AFMT_U8; - if (put_user(val, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - - if (file->f_mode & FMODE_WRITE) - data = val == AFMT_QUERY - ? dev.play_sample_size - : dsp_set_format(file, val); - else - data = val == AFMT_QUERY - ? dev.rec_sample_size - : dsp_set_format(file, val); - - if (put_user(data, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_NONBLOCK: - if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags) && - file->f_mode & FMODE_WRITE) - dev.play_ndelay = 1; - if (file->f_mode & FMODE_READ) - dev.rec_ndelay = 1; - return 0; - - case SNDCTL_DSP_GETCAPS: - val = DSP_CAP_DUPLEX | DSP_CAP_BATCH; - if (put_user(val, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - - if (val < 8000) - val = 8000; - - if (val > 48000) - val = 48000; - - data = val; - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - if (file->f_mode & FMODE_WRITE) - writew(data, lpDAQ + DAQDS_wSampleRate); - if (file->f_mode & FMODE_READ) - writew(data, lpDARQ + DAQDS_wSampleRate); - } - if (file->f_mode & FMODE_WRITE) - dev.play_sample_rate = data; - if (file->f_mode & FMODE_READ) - dev.rec_sample_rate = data; - - if (put_user(data, p)) - return -EFAULT; - return 0; - - case SNDCTL_DSP_CHANNELS: - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - - if (cmd == SNDCTL_DSP_CHANNELS) { - switch (val) { - case 1: - case 2: - data = val; - break; - default: - val = data = 2; - break; - } - } else { - switch (val) { - case 0: - data = 1; - break; - default: - val = 1; - case 1: - data = 2; - break; - } - } - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - if (file->f_mode & FMODE_WRITE) - writew(data, lpDAQ + DAQDS_wChannels); - if (file->f_mode & FMODE_READ) - writew(data, lpDARQ + DAQDS_wChannels); - } - if (file->f_mode & FMODE_WRITE) - dev.play_channels = data; - if (file->f_mode & FMODE_READ) - dev.rec_channels = data; - - if (put_user(val, p)) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - -static int mixer_get(int d) -{ - if (d > 31) - return -EINVAL; - - switch (d) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_PCM: - case SOUND_MIXER_LINE: - case SOUND_MIXER_IMIX: - case SOUND_MIXER_LINE1: -#ifndef MSND_CLASSIC - case SOUND_MIXER_MIC: - case SOUND_MIXER_SYNTH: -#endif - return (dev.left_levels[d] >> 8) * 100 / 0xff | - (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8); - default: - return 0; - } -} - -#define update_volm(a,b) \ - writew((dev.left_levels[a] >> 1) * \ - readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \ - dev.SMA + SMA_##b##Left); \ - writew((dev.right_levels[a] >> 1) * \ - readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \ - dev.SMA + SMA_##b##Right); - -#define update_potm(d,s,ar) \ - writeb((dev.left_levels[d] >> 8) * \ - readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \ - dev.SMA + SMA_##s##Left); \ - writeb((dev.right_levels[d] >> 8) * \ - readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \ - dev.SMA + SMA_##s##Right); \ - if (msnd_send_word(&dev, 0, 0, ar) == 0) \ - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - -#define update_pot(d,s,ar) \ - writeb(dev.left_levels[d] >> 8, \ - dev.SMA + SMA_##s##Left); \ - writeb(dev.right_levels[d] >> 8, \ - dev.SMA + SMA_##s##Right); \ - if (msnd_send_word(&dev, 0, 0, ar) == 0) \ - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - -static int mixer_set(int d, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int bLeft, bRight; - int wLeft, wRight; - int updatemaster = 0; - - if (d > 31) - return -EINVAL; - - bLeft = left * 0xff / 100; - wLeft = left * 0xffff / 100; - - bRight = right * 0xff / 100; - wRight = right * 0xffff / 100; - - dev.left_levels[d] = wLeft; - dev.right_levels[d] = wRight; - - switch (d) { - /* master volume unscaled controls */ - case SOUND_MIXER_LINE: /* line pot control */ - /* scaled by IMIX in digital mix */ - writeb(bLeft, dev.SMA + SMA_bInPotPosLeft); - writeb(bRight, dev.SMA + SMA_bInPotPosRight); - if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - break; -#ifndef MSND_CLASSIC - case SOUND_MIXER_MIC: /* mic pot control */ - /* scaled by IMIX in digital mix */ - writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft); - writeb(bRight, dev.SMA + SMA_bMicPotPosRight); - if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - break; -#endif - case SOUND_MIXER_VOLUME: /* master volume */ - writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft); - writew(wRight, dev.SMA + SMA_wCurrMastVolRight); - /* fall through */ - - case SOUND_MIXER_LINE1: /* aux pot control */ - /* scaled by master volume */ - /* fall through */ - - /* digital controls */ - case SOUND_MIXER_SYNTH: /* synth vol (dsp mix) */ - case SOUND_MIXER_PCM: /* pcm vol (dsp mix) */ - case SOUND_MIXER_IMIX: /* input monitor (dsp mix) */ - /* scaled by master volume */ - updatemaster = 1; - break; - - default: - return 0; - } - - if (updatemaster) { - /* update master volume scaled controls */ - update_volm(SOUND_MIXER_PCM, wCurrPlayVol); - update_volm(SOUND_MIXER_IMIX, wCurrInVol); -#ifndef MSND_CLASSIC - update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol); -#endif - update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); - } - - return mixer_get(d); -} - -static void mixer_setup(void) -{ - update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS); - update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); - update_volm(SOUND_MIXER_PCM, wCurrPlayVol); - update_volm(SOUND_MIXER_IMIX, wCurrInVol); -#ifndef MSND_CLASSIC - update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS); - update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol); -#endif -} - -static unsigned long set_recsrc(unsigned long recsrc) -{ - if (dev.recsrc == recsrc) - return dev.recsrc; -#ifdef HAVE_NORECSRC - else if (recsrc == 0) - dev.recsrc = 0; -#endif - else - dev.recsrc ^= recsrc; - -#ifndef MSND_CLASSIC - if (dev.recsrc & SOUND_MASK_IMIX) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } - else if (dev.recsrc & SOUND_MASK_SYNTH) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } - else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } - else { -#ifdef HAVE_NORECSRC - /* Select no input (?) */ - dev.recsrc = 0; -#else - dev.recsrc = SOUND_MASK_IMIX; - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); -#endif - } -#endif /* MSND_CLASSIC */ - - return dev.recsrc; -} - -static unsigned long force_recsrc(unsigned long recsrc) -{ - dev.recsrc = 0; - return set_recsrc(recsrc); -} - -#define set_mixer_info() \ - memset(&info, 0, sizeof(info)); \ - strlcpy(info.id, "MSNDMIXER", sizeof(info.id)); \ - strlcpy(info.name, "MultiSound Mixer", sizeof(info.name)); - -static int mixer_ioctl(unsigned int cmd, unsigned long arg) -{ - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - set_mixer_info(); - info.modify_counter = dev.mixer_mod_count; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } else if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - set_mixer_info(); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } else if (cmd == SOUND_MIXER_PRIVATE1) { - dev.nresets = 0; - dsp_full_reset(); - return 0; - } else if (((cmd >> 8) & 0xff) == 'M') { - int val = 0; - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = set_recsrc(val); - break; - - default: - if (get_user(val, (int __user *)arg)) - return -EFAULT; - val = mixer_set(cmd & 0xff, val); - break; - } - ++dev.mixer_mod_count; - return put_user(val, (int __user *)arg); - } else { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - val = dev.recsrc; - break; - - case SOUND_MIXER_DEVMASK: - case SOUND_MIXER_STEREODEVS: - val = SOUND_MASK_PCM | - SOUND_MASK_LINE | - SOUND_MASK_IMIX | - SOUND_MASK_LINE1 | -#ifndef MSND_CLASSIC - SOUND_MASK_MIC | - SOUND_MASK_SYNTH | -#endif - SOUND_MASK_VOLUME; - break; - - case SOUND_MIXER_RECMASK: -#ifdef MSND_CLASSIC - val = 0; -#else - val = SOUND_MASK_IMIX | - SOUND_MASK_SYNTH; - if (test_bit(F_HAVEDIGITAL, &dev.flags)) - val |= SOUND_MASK_DIGITAL1; -#endif - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: - if ((val = mixer_get(cmd & 0xff)) < 0) - return -EINVAL; - break; - } - } - - return put_user(val, (int __user *)arg); - } - - return -EINVAL; -} - -static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int minor = iminor(file_inode(file)); - int ret; - - if (cmd == OSS_GETVERSION) { - int sound_version = SOUND_VERSION; - return put_user(sound_version, (int __user *)arg); - } - - ret = -EINVAL; - - mutex_lock(&msnd_pinnacle_mutex); - if (minor == dev.dsp_minor) - ret = dsp_ioctl(file, cmd, arg); - else if (minor == dev.mixer_minor) - ret = mixer_ioctl(cmd, arg); - mutex_unlock(&msnd_pinnacle_mutex); - - return ret; -} - -static void dsp_write_flush(void) -{ - int timeout = get_play_delay_jiffies(dev.DAPF.len); - - if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) - return; - set_bit(F_WRITEFLUSH, &dev.flags); - wait_event_interruptible_timeout( - dev.writeflush, - !test_bit(F_WRITEFLUSH, &dev.flags), - timeout); - clear_bit(F_WRITEFLUSH, &dev.flags); - if (!signal_pending(current)) { - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE)); - } - clear_bit(F_WRITING, &dev.flags); -} - -static void dsp_halt(struct file *file) -{ - if ((file ? file->f_mode : dev.mode) & FMODE_READ) { - clear_bit(F_READING, &dev.flags); - chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP); - msnd_disable_irq(&dev); - if (file) { - printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file); - dev.mode &= ~FMODE_READ; - } - clear_bit(F_AUDIO_READ_INUSE, &dev.flags); - } - if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { - if (test_bit(F_WRITING, &dev.flags)) { - dsp_write_flush(); - chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP); - } - msnd_disable_irq(&dev); - if (file) { - printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file); - dev.mode &= ~FMODE_WRITE; - } - clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags); - } -} - -static int dsp_release(struct file *file) -{ - dsp_halt(file); - return 0; -} - -static int dsp_open(struct file *file) -{ - if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { - set_bit(F_AUDIO_WRITE_INUSE, &dev.flags); - clear_bit(F_WRITING, &dev.flags); - msnd_fifo_make_empty(&dev.DAPF); - reset_play_queue(); - if (file) { - printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file); - dev.mode |= FMODE_WRITE; - } - msnd_enable_irq(&dev); - } - if ((file ? file->f_mode : dev.mode) & FMODE_READ) { - set_bit(F_AUDIO_READ_INUSE, &dev.flags); - clear_bit(F_READING, &dev.flags); - msnd_fifo_make_empty(&dev.DARF); - reset_record_queue(); - if (file) { - printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file); - dev.mode |= FMODE_READ; - } - msnd_enable_irq(&dev); - } - return 0; -} - -static void set_default_play_audio_parameters(void) -{ - dev.play_sample_size = DEFSAMPLESIZE; - dev.play_sample_rate = DEFSAMPLERATE; - dev.play_channels = DEFCHANNELS; -} - -static void set_default_rec_audio_parameters(void) -{ - dev.rec_sample_size = DEFSAMPLESIZE; - dev.rec_sample_rate = DEFSAMPLERATE; - dev.rec_channels = DEFCHANNELS; -} - -static void set_default_audio_parameters(void) -{ - set_default_play_audio_parameters(); - set_default_rec_audio_parameters(); -} - -static int dev_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - int err = 0; - - mutex_lock(&msnd_pinnacle_mutex); - if (minor == dev.dsp_minor) { - if ((file->f_mode & FMODE_WRITE && - test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || - (file->f_mode & FMODE_READ && - test_bit(F_AUDIO_READ_INUSE, &dev.flags))) { - err = -EBUSY; - goto out; - } - - if ((err = dsp_open(file)) >= 0) { - dev.nresets = 0; - if (file->f_mode & FMODE_WRITE) { - set_default_play_audio_parameters(); - if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags)) - dev.play_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; - else - dev.play_ndelay = 0; - } - if (file->f_mode & FMODE_READ) { - set_default_rec_audio_parameters(); - dev.rec_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; - } - } - } - else if (minor == dev.mixer_minor) { - /* nothing */ - } else - err = -EINVAL; -out: - mutex_unlock(&msnd_pinnacle_mutex); - return err; -} - -static int dev_release(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - int err = 0; - - mutex_lock(&msnd_pinnacle_mutex); - if (minor == dev.dsp_minor) - err = dsp_release(file); - else if (minor == dev.mixer_minor) { - /* nothing */ - } else - err = -EINVAL; - mutex_unlock(&msnd_pinnacle_mutex); - return err; -} - -static __inline__ int pack_DARQ_to_DARF(register int bank) -{ - register int size, timeout = 3; - register WORD wTmp; - LPDAQD DAQD; - - /* Increment the tail and check for queue wrap */ - wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size); - if (wTmp > readw(dev.DARQ + JQS_wSize)) - wTmp = 0; - while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--) - udelay(1); - writew(wTmp, dev.DARQ + JQS_wTail); - - /* Get our digital audio queue struct */ - DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF; - - /* Get length of data */ - size = readw(DAQD + DAQDS_wSize); - - /* Read data from the head (unprotected bank 1 access okay - since this is only called inside an interrupt) */ - msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS); - msnd_fifo_write_io( - &dev.DARF, - dev.base + bank * DAR_BUFF_SIZE, - size); - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - - return 1; -} - -static __inline__ int pack_DAPF_to_DAPQ(register int start) -{ - register WORD DAPQ_tail; - register int protect = start, nbanks = 0; - LPDAQD DAQD; - - DAPQ_tail = readw(dev.DAPQ + JQS_wTail); - while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) { - register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); - register int n; - unsigned long flags; - - /* Write the data to the new tail */ - if (protect) { - /* Critical section: protect fifo in non-interrupt */ - spin_lock_irqsave(&dev.lock, flags); - n = msnd_fifo_read_io( - &dev.DAPF, - dev.base + bank_num * DAP_BUFF_SIZE, - DAP_BUFF_SIZE); - spin_unlock_irqrestore(&dev.lock, flags); - } else { - n = msnd_fifo_read_io( - &dev.DAPF, - dev.base + bank_num * DAP_BUFF_SIZE, - DAP_BUFF_SIZE); - } - if (!n) - break; - - if (start) - start = 0; - - /* Get our digital audio queue struct */ - DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF; - - /* Write size of this bank */ - writew(n, DAQD + DAQDS_wSize); - ++nbanks; - - /* Then advance the tail */ - DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); - writew(DAPQ_tail, dev.DAPQ + JQS_wTail); - /* Tell the DSP to play the bank */ - msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); - } - return nbanks; -} - -static int dsp_read(char __user *buf, size_t len) -{ - int count = len; - char *page = (char *)__get_free_page(GFP_KERNEL); - int timeout = get_rec_delay_jiffies(DAR_BUFF_SIZE); - - if (!page) - return -ENOMEM; - - while (count > 0) { - int n, k; - unsigned long flags; - - k = PAGE_SIZE; - if (k > count) - k = count; - - /* Critical section: protect fifo in non-interrupt */ - spin_lock_irqsave(&dev.lock, flags); - n = msnd_fifo_read(&dev.DARF, page, k); - spin_unlock_irqrestore(&dev.lock, flags); - if (copy_to_user(buf, page, n)) { - free_page((unsigned long)page); - return -EFAULT; - } - buf += n; - count -= n; - - if (n == k && count) - continue; - - if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { - dev.last_recbank = -1; - if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) - set_bit(F_READING, &dev.flags); - } - - if (dev.rec_ndelay) { - free_page((unsigned long)page); - return count == len ? -EAGAIN : len - count; - } - - if (count > 0) { - set_bit(F_READBLOCK, &dev.flags); - if (wait_event_interruptible_timeout( - dev.readblock, - test_bit(F_READBLOCK, &dev.flags), - timeout) <= 0) - clear_bit(F_READING, &dev.flags); - if (signal_pending(current)) { - free_page((unsigned long)page); - return -EINTR; - } - } - } - free_page((unsigned long)page); - return len - count; -} - -static int dsp_write(const char __user *buf, size_t len) -{ - int count = len; - char *page = (char *)__get_free_page(GFP_KERNEL); - int timeout = get_play_delay_jiffies(DAP_BUFF_SIZE); - - if (!page) - return -ENOMEM; - - while (count > 0) { - int n, k; - unsigned long flags; - - k = PAGE_SIZE; - if (k > count) - k = count; - - if (copy_from_user(page, buf, k)) { - free_page((unsigned long)page); - return -EFAULT; - } - - /* Critical section: protect fifo in non-interrupt */ - spin_lock_irqsave(&dev.lock, flags); - n = msnd_fifo_write(&dev.DAPF, page, k); - spin_unlock_irqrestore(&dev.lock, flags); - buf += n; - count -= n; - - if (count && n == k) - continue; - - if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { - dev.last_playbank = -1; - if (pack_DAPF_to_DAPQ(1) > 0) - set_bit(F_WRITING, &dev.flags); - } - - if (dev.play_ndelay) { - free_page((unsigned long)page); - return count == len ? -EAGAIN : len - count; - } - - if (count > 0) { - set_bit(F_WRITEBLOCK, &dev.flags); - wait_event_interruptible_timeout( - dev.writeblock, - test_bit(F_WRITEBLOCK, &dev.flags), - timeout); - if (signal_pending(current)) { - free_page((unsigned long)page); - return -EINTR; - } - } - } - - free_page((unsigned long)page); - return len - count; -} - -static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - int minor = iminor(file_inode(file)); - if (minor == dev.dsp_minor) - return dsp_read(buf, count); - else - return -EINVAL; -} - -static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - int minor = iminor(file_inode(file)); - if (minor == dev.dsp_minor) - return dsp_write(buf, count); - else - return -EINVAL; -} - -static __inline__ void eval_dsp_msg(register WORD wMessage) -{ - switch (HIBYTE(wMessage)) { - case HIMT_PLAY_DONE: - if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags)) - break; - dev.last_playbank = LOBYTE(wMessage); - - if (pack_DAPF_to_DAPQ(0) <= 0) { - if (!test_bit(F_WRITEBLOCK, &dev.flags)) { - if (test_and_clear_bit(F_WRITEFLUSH, &dev.flags)) - wake_up_interruptible(&dev.writeflush); - } - clear_bit(F_WRITING, &dev.flags); - } - - if (test_and_clear_bit(F_WRITEBLOCK, &dev.flags)) - wake_up_interruptible(&dev.writeblock); - break; - - case HIMT_RECORD_DONE: - if (dev.last_recbank == LOBYTE(wMessage)) - break; - dev.last_recbank = LOBYTE(wMessage); - - pack_DARQ_to_DARF(dev.last_recbank); - - if (test_and_clear_bit(F_READBLOCK, &dev.flags)) - wake_up_interruptible(&dev.readblock); - break; - - case HIMT_DSP: - switch (LOBYTE(wMessage)) { -#ifndef MSND_CLASSIC - case HIDSP_PLAY_UNDER: -#endif - case HIDSP_INT_PLAY_UNDER: -/* printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */ - clear_bit(F_WRITING, &dev.flags); - break; - - case HIDSP_INT_RECORD_OVER: -/* printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */ - clear_bit(F_READING, &dev.flags); - break; - - default: -/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", - LOBYTE(wMessage), LOBYTE(wMessage)); */ - break; - } - break; - - case HIMT_MIDI_IN_UCHAR: - if (dev.midi_in_interrupt) - (*dev.midi_in_interrupt)(&dev); - break; - - default: -/* printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */ - break; - } -} - -static irqreturn_t intr(int irq, void *dev_id) -{ - /* Send ack to DSP */ - msnd_inb(dev.io + HP_RXL); - - /* Evaluate queued DSP messages */ - while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) { - register WORD wTmp; - - eval_dsp_msg(readw(dev.pwDSPQData + 2*readw(dev.DSPQ + JQS_wHead))); - - if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize)) - writew(0, dev.DSPQ + JQS_wHead); - else - writew(wTmp, dev.DSPQ + JQS_wHead); - } - return IRQ_HANDLED; -} - -static const struct file_operations dev_fileops = { - .owner = THIS_MODULE, - .read = dev_read, - .write = dev_write, - .unlocked_ioctl = dev_ioctl, - .open = dev_open, - .release = dev_release, - .llseek = noop_llseek, -}; - -static int reset_dsp(void) -{ - int timeout = 100; - - msnd_outb(HPDSPRESET_ON, dev.io + HP_DSPR); - mdelay(1); -#ifndef MSND_CLASSIC - dev.info = msnd_inb(dev.io + HP_INFO); -#endif - msnd_outb(HPDSPRESET_OFF, dev.io + HP_DSPR); - mdelay(1); - while (timeout-- > 0) { - if (msnd_inb(dev.io + HP_CVR) == HP_CVR_DEF) - return 0; - mdelay(1); - } - printk(KERN_ERR LOGNAME ": Cannot reset DSP\n"); - - return -EIO; -} - -static int __init probe_multisound(void) -{ -#ifndef MSND_CLASSIC - char *xv, *rev = NULL; - char *pin = "Pinnacle", *fiji = "Fiji"; - char *pinfiji = "Pinnacle/Fiji"; -#endif - - if (!request_region(dev.io, dev.numio, "probing")) { - printk(KERN_ERR LOGNAME ": I/O port conflict\n"); - return -ENODEV; - } - - if (reset_dsp() < 0) { - release_region(dev.io, dev.numio); - return -ENODEV; - } - -#ifdef MSND_CLASSIC - dev.name = "Classic/Tahiti/Monterey"; - printk(KERN_INFO LOGNAME ": %s, " -#else - switch (dev.info >> 4) { - case 0xf: xv = "<= 1.15"; break; - case 0x1: xv = "1.18/1.2"; break; - case 0x2: xv = "1.3"; break; - case 0x3: xv = "1.4"; break; - default: xv = "unknown"; break; - } - - switch (dev.info & 0x7) { - case 0x0: rev = "I"; dev.name = pin; break; - case 0x1: rev = "F"; dev.name = pin; break; - case 0x2: rev = "G"; dev.name = pin; break; - case 0x3: rev = "H"; dev.name = pin; break; - case 0x4: rev = "E"; dev.name = fiji; break; - case 0x5: rev = "C"; dev.name = fiji; break; - case 0x6: rev = "D"; dev.name = fiji; break; - case 0x7: - rev = "A-B (Fiji) or A-E (Pinnacle)"; - dev.name = pinfiji; - break; - } - printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, " -#endif /* MSND_CLASSIC */ - "I/O 0x%x-0x%x, IRQ %d, memory mapped to %p-%p\n", - dev.name, -#ifndef MSND_CLASSIC - rev, xv, -#endif - dev.io, dev.io + dev.numio - 1, - dev.irq, - dev.base, dev.base + 0x7fff); - - release_region(dev.io, dev.numio); - return 0; -} - -static int init_sma(void) -{ - static int initted; - WORD mastVolLeft, mastVolRight; - unsigned long flags; - -#ifdef MSND_CLASSIC - msnd_outb(dev.memid, dev.io + HP_MEMM); -#endif - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - if (initted) { - mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft); - mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight); - } else - mastVolLeft = mastVolRight = 0; - memset_io(dev.base, 0, 0x8000); - - /* Critical section: bank 1 access */ - spin_lock_irqsave(&dev.lock, flags); - msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS); - memset_io(dev.base, 0, 0x8000); - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); - spin_unlock_irqrestore(&dev.lock, flags); - - dev.pwDSPQData = (dev.base + DSPQ_DATA_BUFF); - dev.pwMODQData = (dev.base + MODQ_DATA_BUFF); - dev.pwMIDQData = (dev.base + MIDQ_DATA_BUFF); - - /* Motorola 56k shared memory base */ - dev.SMA = dev.base + SMA_STRUCT_START; - - /* Digital audio play queue */ - dev.DAPQ = dev.base + DAPQ_OFFSET; - msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE); - - /* Digital audio record queue */ - dev.DARQ = dev.base + DARQ_OFFSET; - msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); - - /* MIDI out queue */ - dev.MODQ = dev.base + MODQ_OFFSET; - msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE); - - /* MIDI in queue */ - dev.MIDQ = dev.base + MIDQ_OFFSET; - msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE); - - /* DSP -> host message queue */ - dev.DSPQ = dev.base + DSPQ_OFFSET; - msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE); - - /* Setup some DSP values */ -#ifndef MSND_CLASSIC - writew(1, dev.SMA + SMA_wCurrPlayFormat); - writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize); - writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels); - writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate); -#endif - writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD); - writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft); - writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight); -#ifndef MSND_CLASSIC - writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch); - writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate); -#endif - writew(0x303, dev.SMA + SMA_wCurrInputTagBits); - - initted = 1; - - return 0; -} - -static int __init calibrate_adc(WORD srate) -{ - writew(srate, dev.SMA + SMA_wCalFreqAtoD); - if (dev.calibrate_signal == 0) - writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) - | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags); - else - writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) - & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags); - if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { - schedule_timeout_interruptible(HZ / 3); - return 0; - } - printk(KERN_WARNING LOGNAME ": ADC calibration failed\n"); - - return -EIO; -} - -static int upload_dsp_code(void) -{ - int ret = 0; - - msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); -#ifndef HAVE_DSPCODEH - INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE); - if (!INITCODE) { - printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE); - return -EBUSY; - } - - PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE); - if (!PERMCODE) { - printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE); - vfree(INITCODE); - return -EBUSY; - } -#endif - memcpy_toio(dev.base, PERMCODE, PERMCODESIZE); - if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) { - printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n"); - ret = -ENODEV; - goto out; - } -#ifdef HAVE_DSPCODEH - printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n"); -#else - printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n"); -#endif - -out: -#ifndef HAVE_DSPCODEH - vfree(INITCODE); - vfree(PERMCODE); -#endif - - return ret; -} - -#ifdef MSND_CLASSIC -static void reset_proteus(void) -{ - msnd_outb(HPPRORESET_ON, dev.io + HP_PROR); - mdelay(TIME_PRO_RESET); - msnd_outb(HPPRORESET_OFF, dev.io + HP_PROR); - mdelay(TIME_PRO_RESET_DONE); -} -#endif - -static int initialize(void) -{ - int err, timeout; - -#ifdef MSND_CLASSIC - msnd_outb(HPWAITSTATE_0, dev.io + HP_WAIT); - msnd_outb(HPBITMODE_16, dev.io + HP_BITM); - - reset_proteus(); -#endif - if ((err = init_sma()) < 0) { - printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n"); - return err; - } - - if ((err = reset_dsp()) < 0) - return err; - - if ((err = upload_dsp_code()) < 0) { - printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n"); - return err; - } - - timeout = 200; - while (readw(dev.base)) { - mdelay(1); - if (!timeout--) { - printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n"); - return -EIO; - } - } - - mixer_setup(); - - return 0; -} - -static int dsp_full_reset(void) -{ - int rv; - - if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10) - return 0; - - set_bit(F_RESETTING, &dev.flags); - printk(KERN_INFO LOGNAME ": DSP reset\n"); - dsp_halt(NULL); /* Unconditionally halt */ - if ((rv = initialize())) - printk(KERN_WARNING LOGNAME ": DSP reset failed\n"); - force_recsrc(dev.recsrc); - dsp_open(NULL); - clear_bit(F_RESETTING, &dev.flags); - - return rv; -} - -static int __init attach_multisound(void) -{ - int err; - - if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); - return err; - } - if (request_region(dev.io, dev.numio, dev.name) == NULL) { - free_irq(dev.irq, &dev); - return -EBUSY; - } - - err = dsp_full_reset(); - if (err < 0) { - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return err; - } - - if ((err = msnd_register(&dev)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n"); - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return err; - } - - if ((dev.dsp_minor = register_sound_dsp(&dev_fileops, -1)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n"); - msnd_unregister(&dev); - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return dev.dsp_minor; - } - - if ((dev.mixer_minor = register_sound_mixer(&dev_fileops, -1)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n"); - unregister_sound_mixer(dev.mixer_minor); - msnd_unregister(&dev); - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - return dev.mixer_minor; - } - - dev.ext_midi_dev = dev.hdr_midi_dev = -1; - - disable_irq(dev.irq); - calibrate_adc(dev.play_sample_rate); -#ifndef MSND_CLASSIC - force_recsrc(SOUND_MASK_IMIX); -#endif - - return 0; -} - -static void __exit unload_multisound(void) -{ - release_region(dev.io, dev.numio); - free_irq(dev.irq, &dev); - unregister_sound_mixer(dev.mixer_minor); - unregister_sound_dsp(dev.dsp_minor); - msnd_unregister(&dev); -} - -#ifndef MSND_CLASSIC - -/* Pinnacle/Fiji Logical Device Configuration */ - -static int __init msnd_write_cfg(int cfg, int reg, int value) -{ - msnd_outb(reg, cfg); - msnd_outb(value, cfg + 1); - if (value != msnd_inb(cfg + 1)) { - printk(KERN_ERR LOGNAME ": msnd_write_cfg: I/O error\n"); - return -EIO; - } - return 0; -} - -static int __init msnd_write_cfg_io0(int cfg, int num, WORD io) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io))) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_io1(int cfg, int num, WORD io) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io))) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_irq(int cfg, int num, WORD irq) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE)) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_mem(int cfg, int num, int mem) -{ - WORD wmem; - - mem >>= 8; - mem &= 0xfff; - wmem = (WORD)mem; - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem))) - return -EIO; - if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem))) - return -EIO; - if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT))) - return -EIO; - return 0; -} - -static int __init msnd_activate_logical(int cfg, int num) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE)) - return -EIO; - return 0; -} - -static int __init msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem) -{ - if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) - return -EIO; - if (msnd_write_cfg_io0(cfg, num, io0)) - return -EIO; - if (msnd_write_cfg_io1(cfg, num, io1)) - return -EIO; - if (msnd_write_cfg_irq(cfg, num, irq)) - return -EIO; - if (msnd_write_cfg_mem(cfg, num, mem)) - return -EIO; - if (msnd_activate_logical(cfg, num)) - return -EIO; - return 0; -} - -typedef struct msnd_pinnacle_cfg_device { - WORD io0, io1, irq; - int mem; -} msnd_pinnacle_cfg_t[4]; - -static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device) -{ - int i; - - /* Reset devices if told to */ - if (reset) { - printk(KERN_INFO LOGNAME ": Resetting all devices\n"); - for (i = 0; i < 4; ++i) - if (msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0)) - return -EIO; - } - - /* Configure specified devices */ - for (i = 0; i < 4; ++i) { - - switch (i) { - case 0: /* DSP */ - if (!(device[i].io0 && device[i].irq && device[i].mem)) - continue; - break; - case 1: /* MPU */ - if (!(device[i].io0 && device[i].irq)) - continue; - printk(KERN_INFO LOGNAME - ": Configuring MPU to I/O 0x%x IRQ %d\n", - device[i].io0, device[i].irq); - break; - case 2: /* IDE */ - if (!(device[i].io0 && device[i].io1 && device[i].irq)) - continue; - printk(KERN_INFO LOGNAME - ": Configuring IDE to I/O 0x%x, 0x%x IRQ %d\n", - device[i].io0, device[i].io1, device[i].irq); - break; - case 3: /* Joystick */ - if (!(device[i].io0)) - continue; - printk(KERN_INFO LOGNAME - ": Configuring joystick to I/O 0x%x\n", - device[i].io0); - break; - } - - /* Configure the device */ - if (msnd_write_cfg_logical(cfg, i, device[i].io0, device[i].io1, device[i].irq, device[i].mem)) - return -EIO; - } - - return 0; -} -#endif - -#ifdef MODULE -MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>"); -MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver"); -MODULE_LICENSE("GPL"); - -static int io __initdata = -1; -static int irq __initdata = -1; -static int mem __initdata = -1; -static int write_ndelay __initdata = -1; - -#ifndef MSND_CLASSIC -/* Pinnacle/Fiji non-PnP Config Port */ -static int cfg __initdata = -1; - -/* Extra Peripheral Configuration */ -static int reset __initdata = 0; -static int mpu_io __initdata = 0; -static int mpu_irq __initdata = 0; -static int ide_io0 __initdata = 0; -static int ide_io1 __initdata = 0; -static int ide_irq __initdata = 0; -static int joystick_io __initdata = 0; - -/* If we have the digital daugherboard... */ -static bool digital __initdata = false; -#endif - -static int fifosize __initdata = DEFFIFOSIZE; -static int calibrate_signal __initdata = 0; - -#else /* not a module */ - -static int write_ndelay __initdata = -1; - -#ifdef MSND_CLASSIC -static int io __initdata = CONFIG_MSNDCLAS_IO; -static int irq __initdata = CONFIG_MSNDCLAS_IRQ; -static int mem __initdata = CONFIG_MSNDCLAS_MEM; -#else /* Pinnacle/Fiji */ - -static int io __initdata = CONFIG_MSNDPIN_IO; -static int irq __initdata = CONFIG_MSNDPIN_IRQ; -static int mem __initdata = CONFIG_MSNDPIN_MEM; - -/* Pinnacle/Fiji non-PnP Config Port */ -#ifdef CONFIG_MSNDPIN_NONPNP -# ifndef CONFIG_MSNDPIN_CFG -# define CONFIG_MSNDPIN_CFG 0x250 -# endif -#else -# ifdef CONFIG_MSNDPIN_CFG -# undef CONFIG_MSNDPIN_CFG -# endif -# define CONFIG_MSNDPIN_CFG -1 -#endif -static int cfg __initdata = CONFIG_MSNDPIN_CFG; -/* If not a module, we don't need to bother with reset=1 */ -static int reset; - -/* Extra Peripheral Configuration (Default: Disable) */ -#ifndef CONFIG_MSNDPIN_MPU_IO -# define CONFIG_MSNDPIN_MPU_IO 0 -#endif -static int mpu_io __initdata = CONFIG_MSNDPIN_MPU_IO; - -#ifndef CONFIG_MSNDPIN_MPU_IRQ -# define CONFIG_MSNDPIN_MPU_IRQ 0 -#endif -static int mpu_irq __initdata = CONFIG_MSNDPIN_MPU_IRQ; - -#ifndef CONFIG_MSNDPIN_IDE_IO0 -# define CONFIG_MSNDPIN_IDE_IO0 0 -#endif -static int ide_io0 __initdata = CONFIG_MSNDPIN_IDE_IO0; - -#ifndef CONFIG_MSNDPIN_IDE_IO1 -# define CONFIG_MSNDPIN_IDE_IO1 0 -#endif -static int ide_io1 __initdata = CONFIG_MSNDPIN_IDE_IO1; - -#ifndef CONFIG_MSNDPIN_IDE_IRQ -# define CONFIG_MSNDPIN_IDE_IRQ 0 -#endif -static int ide_irq __initdata = CONFIG_MSNDPIN_IDE_IRQ; - -#ifndef CONFIG_MSNDPIN_JOYSTICK_IO -# define CONFIG_MSNDPIN_JOYSTICK_IO 0 -#endif -static int joystick_io __initdata = CONFIG_MSNDPIN_JOYSTICK_IO; - -/* Have SPDIF (Digital) Daughterboard */ -#ifndef CONFIG_MSNDPIN_DIGITAL -# define CONFIG_MSNDPIN_DIGITAL 0 -#endif -static bool digital __initdata = CONFIG_MSNDPIN_DIGITAL; - -#endif /* MSND_CLASSIC */ - -#ifndef CONFIG_MSND_FIFOSIZE -# define CONFIG_MSND_FIFOSIZE DEFFIFOSIZE -#endif -static int fifosize __initdata = CONFIG_MSND_FIFOSIZE; - -#ifndef CONFIG_MSND_CALSIGNAL -# define CONFIG_MSND_CALSIGNAL 0 -#endif -static int -calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL; -#endif /* MODULE */ - -module_param_hw (io, int, ioport, 0); -module_param_hw (irq, int, irq, 0); -module_param_hw (mem, int, iomem, 0); -module_param (write_ndelay, int, 0); -module_param (fifosize, int, 0); -module_param (calibrate_signal, int, 0); -#ifndef MSND_CLASSIC -module_param (digital, bool, 0); -module_param_hw (cfg, int, ioport, 0); -module_param (reset, int, 0); -module_param_hw (mpu_io, int, ioport, 0); -module_param_hw (mpu_irq, int, irq, 0); -module_param_hw (ide_io0, int, ioport, 0); -module_param_hw (ide_io1, int, ioport, 0); -module_param_hw (ide_irq, int, irq, 0); -module_param_hw (joystick_io, int, ioport, 0); -#endif - -static int __init msnd_init(void) -{ - int err; -#ifndef MSND_CLASSIC - static msnd_pinnacle_cfg_t pinnacle_devs; -#endif /* MSND_CLASSIC */ - - printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version " - VERSION ", Copyright (C) 1998 Andrew Veliath\n"); - - if (io == -1 || irq == -1 || mem == -1) - printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n"); - -#ifdef MSND_CLASSIC - if (io == -1 || - !(io == 0x290 || - io == 0x260 || - io == 0x250 || - io == 0x240 || - io == 0x230 || - io == 0x220 || - io == 0x210 || - io == 0x3e0)) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n"); - return -EINVAL; - } -#else - if (io == -1 || - io < 0x100 || - io > 0x3e0 || - (io % 0x10) != 0) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must within the range 0x100 to 0x3E0 and must be evenly divisible by 0x10\n"); - return -EINVAL; - } -#endif /* MSND_CLASSIC */ - - if (irq == -1 || - !(irq == 5 || - irq == 7 || - irq == 9 || - irq == 10 || - irq == 11 || - irq == 12)) { - printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n"); - return -EINVAL; - } - - if (mem == -1 || - !(mem == 0xb0000 || - mem == 0xc8000 || - mem == 0xd0000 || - mem == 0xd8000 || - mem == 0xe0000 || - mem == 0xe8000)) { - printk(KERN_ERR LOGNAME ": \"mem\" - must be set to " - "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); - return -EINVAL; - } - -#ifdef MSND_CLASSIC - switch (irq) { - case 5: dev.irqid = HPIRQ_5; break; - case 7: dev.irqid = HPIRQ_7; break; - case 9: dev.irqid = HPIRQ_9; break; - case 10: dev.irqid = HPIRQ_10; break; - case 11: dev.irqid = HPIRQ_11; break; - case 12: dev.irqid = HPIRQ_12; break; - } - - switch (mem) { - case 0xb0000: dev.memid = HPMEM_B000; break; - case 0xc8000: dev.memid = HPMEM_C800; break; - case 0xd0000: dev.memid = HPMEM_D000; break; - case 0xd8000: dev.memid = HPMEM_D800; break; - case 0xe0000: dev.memid = HPMEM_E000; break; - case 0xe8000: dev.memid = HPMEM_E800; break; - } -#else - if (cfg == -1) { - printk(KERN_INFO LOGNAME ": Assuming PnP mode\n"); - } else if (cfg != 0x250 && cfg != 0x260 && cfg != 0x270) { - printk(KERN_INFO LOGNAME ": Config port must be 0x250, 0x260 or 0x270 (or unspecified for PnP mode)\n"); - return -EINVAL; - } else { - printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%x\n", cfg); - - /* DSP */ - pinnacle_devs[0].io0 = io; - pinnacle_devs[0].irq = irq; - pinnacle_devs[0].mem = mem; - - /* The following are Pinnacle specific */ - - /* MPU */ - pinnacle_devs[1].io0 = mpu_io; - pinnacle_devs[1].irq = mpu_irq; - - /* IDE */ - pinnacle_devs[2].io0 = ide_io0; - pinnacle_devs[2].io1 = ide_io1; - pinnacle_devs[2].irq = ide_irq; - - /* Joystick */ - pinnacle_devs[3].io0 = joystick_io; - - if (!request_region(cfg, 2, "Pinnacle/Fiji Config")) { - printk(KERN_ERR LOGNAME ": Config port 0x%x conflict\n", cfg); - return -EIO; - } - - if (msnd_pinnacle_cfg_devices(cfg, reset, pinnacle_devs)) { - printk(KERN_ERR LOGNAME ": Device configuration error\n"); - release_region(cfg, 2); - return -EIO; - } - release_region(cfg, 2); - } -#endif /* MSND_CLASSIC */ - - if (fifosize < 16) - fifosize = 16; - - if (fifosize > 1024) - fifosize = 1024; - - set_default_audio_parameters(); -#ifdef MSND_CLASSIC - dev.type = msndClassic; -#else - dev.type = msndPinnacle; -#endif - dev.io = io; - dev.numio = DSP_NUMIO; - dev.irq = irq; - dev.base = ioremap(mem, 0x8000); - dev.fifosize = fifosize * 1024; - dev.calibrate_signal = calibrate_signal ? 1 : 0; - dev.recsrc = 0; - dev.dspq_data_buff = DSPQ_DATA_BUFF; - dev.dspq_buff_size = DSPQ_BUFF_SIZE; - if (write_ndelay == -1) - write_ndelay = CONFIG_MSND_WRITE_NDELAY; - if (write_ndelay) - clear_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); - else - set_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); -#ifndef MSND_CLASSIC - if (digital) - set_bit(F_HAVEDIGITAL, &dev.flags); -#endif - init_waitqueue_head(&dev.writeblock); - init_waitqueue_head(&dev.readblock); - init_waitqueue_head(&dev.writeflush); - msnd_fifo_init(&dev.DAPF); - msnd_fifo_init(&dev.DARF); - spin_lock_init(&dev.lock); - printk(KERN_INFO LOGNAME ": %u byte audio FIFOs (x2)\n", dev.fifosize); - if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n"); - return err; - } - - if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n"); - msnd_fifo_free(&dev.DAPF); - return err; - } - - if ((err = probe_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Probe failed\n"); - msnd_fifo_free(&dev.DAPF); - msnd_fifo_free(&dev.DARF); - return err; - } - - if ((err = attach_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Attach failed\n"); - msnd_fifo_free(&dev.DAPF); - msnd_fifo_free(&dev.DARF); - return err; - } - - return 0; -} - -static void __exit msdn_cleanup(void) -{ - unload_multisound(); - msnd_fifo_free(&dev.DAPF); - msnd_fifo_free(&dev.DARF); -} - -module_init(msnd_init); -module_exit(msdn_cleanup); diff --git a/sound/oss/msnd_pinnacle.h b/sound/oss/msnd_pinnacle.h deleted file mode 100644 index c18d66cbbe3f..000000000000 --- a/sound/oss/msnd_pinnacle.h +++ /dev/null @@ -1,246 +0,0 @@ -/********************************************************************* - * - * msnd_pinnacle.h - * - * Turtle Beach MultiSound Sound Card Driver for Linux - * - * Some parts of this header file were derived from the Turtle Beach - * MultiSound Driver Development Kit. - * - * Copyright (C) 1998 Andrew Veliath - * Copyright (C) 1993 Turtle Beach Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ********************************************************************/ -#ifndef __MSND_PINNACLE_H -#define __MSND_PINNACLE_H - - -#define DSP_NUMIO 0x08 - -#define IREG_LOGDEVICE 0x07 -#define IREG_ACTIVATE 0x30 -#define LD_ACTIVATE 0x01 -#define LD_DISACTIVATE 0x00 -#define IREG_EECONTROL 0x3F -#define IREG_MEMBASEHI 0x40 -#define IREG_MEMBASELO 0x41 -#define IREG_MEMCONTROL 0x42 -#define IREG_MEMRANGEHI 0x43 -#define IREG_MEMRANGELO 0x44 -#define MEMTYPE_8BIT 0x00 -#define MEMTYPE_16BIT 0x02 -#define MEMTYPE_RANGE 0x00 -#define MEMTYPE_HIADDR 0x01 -#define IREG_IO0_BASEHI 0x60 -#define IREG_IO0_BASELO 0x61 -#define IREG_IO1_BASEHI 0x62 -#define IREG_IO1_BASELO 0x63 -#define IREG_IRQ_NUMBER 0x70 -#define IREG_IRQ_TYPE 0x71 -#define IRQTYPE_HIGH 0x02 -#define IRQTYPE_LOW 0x00 -#define IRQTYPE_LEVEL 0x01 -#define IRQTYPE_EDGE 0x00 - -#define HP_DSPR 0x04 -#define HP_BLKS 0x04 - -#define HPDSPRESET_OFF 2 -#define HPDSPRESET_ON 0 - -#define HPBLKSEL_0 2 -#define HPBLKSEL_1 3 - -#define HIMT_DAT_OFF 0x03 - -#define HIDSP_PLAY_UNDER 0x00 -#define HIDSP_INT_PLAY_UNDER 0x01 -#define HIDSP_SSI_TX_UNDER 0x02 -#define HIDSP_RECQ_OVERFLOW 0x08 -#define HIDSP_INT_RECORD_OVER 0x09 -#define HIDSP_SSI_RX_OVERFLOW 0x0a - -#define HIDSP_MIDI_IN_OVER 0x10 - -#define HIDSP_MIDI_FRAME_ERR 0x11 -#define HIDSP_MIDI_PARITY_ERR 0x12 -#define HIDSP_MIDI_OVERRUN_ERR 0x13 - -#define HIDSP_INPUT_CLIPPING 0x20 -#define HIDSP_MIX_CLIPPING 0x30 -#define HIDSP_DAT_IN_OFF 0x21 - -#define HDEXAR_SET_ANA_IN 0 -#define HDEXAR_CLEAR_PEAKS 1 -#define HDEXAR_IN_SET_POTS 2 -#define HDEXAR_AUX_SET_POTS 3 -#define HDEXAR_CAL_A_TO_D 4 -#define HDEXAR_RD_EXT_DSP_BITS 5 - -#define HDEXAR_SET_SYNTH_IN 4 -#define HDEXAR_READ_DAT_IN 5 -#define HDEXAR_MIC_SET_POTS 6 -#define HDEXAR_SET_DAT_IN 7 - -#define HDEXAR_SET_SYNTH_48 8 -#define HDEXAR_SET_SYNTH_44 9 - -#define TIME_PRO_RESET_DONE 0x028A -#define TIME_PRO_SYSEX 0x001E -#define TIME_PRO_RESET 0x0032 - -#define AGND 0x01 -#define SIGNAL 0x02 - -#define EXT_DSP_BIT_DCAL 0x0001 -#define EXT_DSP_BIT_MIDI_CON 0x0002 - -#define BUFFSIZE 0x8000 -#define HOSTQ_SIZE 0x40 - -#define SRAM_CNTL_START 0x7F00 -#define SMA_STRUCT_START 0x7F40 - -#define DAP_BUFF_SIZE 0x2400 -#define DAR_BUFF_SIZE 0x2000 - -#define DAPQ_STRUCT_SIZE 0x10 -#define DARQ_STRUCT_SIZE 0x10 -#define DAPQ_BUFF_SIZE (3 * 0x10) -#define DARQ_BUFF_SIZE (3 * 0x10) -#define MODQ_BUFF_SIZE 0x400 -#define MIDQ_BUFF_SIZE 0x800 -#define DSPQ_BUFF_SIZE 0x5A0 - -#define DAPQ_DATA_BUFF 0x6C00 -#define DARQ_DATA_BUFF 0x6C30 -#define MODQ_DATA_BUFF 0x6C60 -#define MIDQ_DATA_BUFF 0x7060 -#define DSPQ_DATA_BUFF 0x7860 - -#define DAPQ_OFFSET SRAM_CNTL_START -#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) -#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) -#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) -#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) - -#define MOP_WAVEHDR 0 -#define MOP_EXTOUT 1 -#define MOP_HWINIT 0xfe -#define MOP_NONE 0xff -#define MOP_MAX 1 - -#define MIP_EXTIN 0 -#define MIP_WAVEHDR 1 -#define MIP_HWINIT 0xfe -#define MIP_MAX 1 - -/* Pinnacle/Fiji SMA Common Data */ -#define SMA_wCurrPlayBytes 0x0000 -#define SMA_wCurrRecordBytes 0x0002 -#define SMA_wCurrPlayVolLeft 0x0004 -#define SMA_wCurrPlayVolRight 0x0006 -#define SMA_wCurrInVolLeft 0x0008 -#define SMA_wCurrInVolRight 0x000a -#define SMA_wCurrMHdrVolLeft 0x000c -#define SMA_wCurrMHdrVolRight 0x000e -#define SMA_dwCurrPlayPitch 0x0010 -#define SMA_dwCurrPlayRate 0x0014 -#define SMA_wCurrMIDIIOPatch 0x0018 -#define SMA_wCurrPlayFormat 0x001a -#define SMA_wCurrPlaySampleSize 0x001c -#define SMA_wCurrPlayChannels 0x001e -#define SMA_wCurrPlaySampleRate 0x0020 -#define SMA_wCurrRecordFormat 0x0022 -#define SMA_wCurrRecordSampleSize 0x0024 -#define SMA_wCurrRecordChannels 0x0026 -#define SMA_wCurrRecordSampleRate 0x0028 -#define SMA_wCurrDSPStatusFlags 0x002a -#define SMA_wCurrHostStatusFlags 0x002c -#define SMA_wCurrInputTagBits 0x002e -#define SMA_wCurrLeftPeak 0x0030 -#define SMA_wCurrRightPeak 0x0032 -#define SMA_bMicPotPosLeft 0x0034 -#define SMA_bMicPotPosRight 0x0035 -#define SMA_bMicPotMaxLeft 0x0036 -#define SMA_bMicPotMaxRight 0x0037 -#define SMA_bInPotPosLeft 0x0038 -#define SMA_bInPotPosRight 0x0039 -#define SMA_bAuxPotPosLeft 0x003a -#define SMA_bAuxPotPosRight 0x003b -#define SMA_bInPotMaxLeft 0x003c -#define SMA_bInPotMaxRight 0x003d -#define SMA_bAuxPotMaxLeft 0x003e -#define SMA_bAuxPotMaxRight 0x003f -#define SMA_bInPotMaxMethod 0x0040 -#define SMA_bAuxPotMaxMethod 0x0041 -#define SMA_wCurrMastVolLeft 0x0042 -#define SMA_wCurrMastVolRight 0x0044 -#define SMA_wCalFreqAtoD 0x0046 -#define SMA_wCurrAuxVolLeft 0x0048 -#define SMA_wCurrAuxVolRight 0x004a -#define SMA_wCurrPlay1VolLeft 0x004c -#define SMA_wCurrPlay1VolRight 0x004e -#define SMA_wCurrPlay2VolLeft 0x0050 -#define SMA_wCurrPlay2VolRight 0x0052 -#define SMA_wCurrPlay3VolLeft 0x0054 -#define SMA_wCurrPlay3VolRight 0x0056 -#define SMA_wCurrPlay4VolLeft 0x0058 -#define SMA_wCurrPlay4VolRight 0x005a -#define SMA_wCurrPlay1PeakLeft 0x005c -#define SMA_wCurrPlay1PeakRight 0x005e -#define SMA_wCurrPlay2PeakLeft 0x0060 -#define SMA_wCurrPlay2PeakRight 0x0062 -#define SMA_wCurrPlay3PeakLeft 0x0064 -#define SMA_wCurrPlay3PeakRight 0x0066 -#define SMA_wCurrPlay4PeakLeft 0x0068 -#define SMA_wCurrPlay4PeakRight 0x006a -#define SMA_wCurrPlayPeakLeft 0x006c -#define SMA_wCurrPlayPeakRight 0x006e -#define SMA_wCurrDATSR 0x0070 -#define SMA_wCurrDATRXCHNL 0x0072 -#define SMA_wCurrDATTXCHNL 0x0074 -#define SMA_wCurrDATRXRate 0x0076 -#define SMA_dwDSPPlayCount 0x0078 -#define SMA__size 0x007c - -#ifdef HAVE_DSPCODEH -# include "pndsperm.c" -# include "pndspini.c" -# define PERMCODE pndsperm -# define INITCODE pndspini -# define PERMCODESIZE sizeof(pndsperm) -# define INITCODESIZE sizeof(pndspini) -#else -# ifndef CONFIG_MSNDPIN_INIT_FILE -# define CONFIG_MSNDPIN_INIT_FILE \ - "/etc/sound/pndspini.bin" -# endif -# ifndef CONFIG_MSNDPIN_PERM_FILE -# define CONFIG_MSNDPIN_PERM_FILE \ - "/etc/sound/pndsperm.bin" -# endif -# define PERMCODEFILE CONFIG_MSNDPIN_PERM_FILE -# define INITCODEFILE CONFIG_MSNDPIN_INIT_FILE -# define PERMCODE dspini -# define INITCODE permini -# define PERMCODESIZE sizeof_dspini -# define INITCODESIZE sizeof_permini -#endif -#define LONGNAME "MultiSound (Pinnacle/Fiji)" - -#endif /* __MSND_PINNACLE_H */ diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c deleted file mode 100644 index f0f5b5be6314..000000000000 --- a/sound/oss/opl3.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * sound/oss/opl3.c - * - * A low level driver for Yamaha YM3812 and OPL-3 -chips - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Changes - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, fixed sound_mem allocs. - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo get rid of check_region, use request_region for - * OPL4, release it on exit, some cleanups. - * - * Status - * Believed to work. Badly needs rewriting a bit to support multiple - * OPL3 devices. - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/delay.h> - -/* - * Major improvements to the FM handling 30AUG92 by Rob Hooft, - * hooft@chem.ruu.nl - */ - -#include "sound_config.h" - -#include "opl3_hw.h" - -#define MAX_VOICE 18 -#define OFFS_4OP 11 - -struct voice_info -{ - unsigned char keyon_byte; - long bender; - long bender_range; - unsigned long orig_freq; - unsigned long current_freq; - int volume; - int mode; - int panning; /* 0xffff means not set */ -}; - -struct opl_devinfo -{ - int base; - int left_io, right_io; - int nr_voice; - int lv_map[MAX_VOICE]; - - struct voice_info voc[MAX_VOICE]; - struct voice_alloc_info *v_alloc; - struct channel_info *chn_info; - - struct sbi_instrument i_map[SBFM_MAXINSTR]; - struct sbi_instrument *act_i[MAX_VOICE]; - - struct synth_info fm_info; - - int busy; - int model; - unsigned char cmask; - - int is_opl4; -}; - -static struct opl_devinfo *devc = NULL; - -static int detected_model; - -static int store_instr(int instr_no, struct sbi_instrument *instr); -static void freq_to_fnum(int freq, int *block, int *fnum); -static void opl3_command(int io_addr, unsigned int addr, unsigned int val); -static int opl3_kill_note(int dev, int voice, int note, int velocity); - -static void enter_4op_mode(void) -{ - int i; - static int v4op[MAX_VOICE] = { - 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17 - }; - - devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */ - opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f); - - for (i = 0; i < 3; i++) - pv_map[i].voice_mode = 4; - for (i = 3; i < 6; i++) - pv_map[i].voice_mode = 0; - - for (i = 9; i < 12; i++) - pv_map[i].voice_mode = 4; - for (i = 12; i < 15; i++) - pv_map[i].voice_mode = 0; - - for (i = 0; i < 12; i++) - devc->lv_map[i] = v4op[i]; - devc->v_alloc->max_voice = devc->nr_voice = 12; -} - -static int opl3_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - struct sbi_instrument ins; - - switch (cmd) { - case SNDCTL_FM_LOAD_INSTR: - printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); - if (copy_from_user(&ins, arg, sizeof(ins))) - return -EFAULT; - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { - printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - return store_instr(ins.channel, &ins); - - case SNDCTL_SYNTH_INFO: - devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - if (copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info))) - return -EFAULT; - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - - case SNDCTL_FM_4OP_ENABLE: - if (devc->model == 2) - enter_4op_mode(); - return 0; - - default: - return -EINVAL; - } -} - -static int opl3_detect(int ioaddr) -{ - /* - * This function returns 1 if the FM chip is present at the given I/O port - * The detection algorithm plays with the timer built in the FM chip and - * looks for a change in the status register. - * - * Note! The timers of the FM chip are not connected to AdLib (and compatible) - * boards. - * - * Note2! The chip is initialized if detected. - */ - - unsigned char stat1, signature; - int i; - - if (devc != NULL) - { - printk(KERN_ERR "opl3: Only one OPL3 supported.\n"); - return 0; - } - - devc = kzalloc(sizeof(*devc), GFP_KERNEL); - - if (devc == NULL) - { - printk(KERN_ERR "opl3: Can't allocate memory for the device control " - "structure \n "); - return 0; - } - - strcpy(devc->fm_info.name, "OPL2"); - - if (!request_region(ioaddr, 4, devc->fm_info.name)) { - printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr); - goto cleanup_devc; - } - - devc->base = ioaddr; - - /* Reset timers 1 and 2 */ - opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - - /* Reset the IRQ of the FM chip */ - opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); - - signature = stat1 = inb(ioaddr); /* Status register */ - - if (signature != 0x00 && signature != 0x06 && signature != 0x02 && - signature != 0x0f) - { - MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature)); - goto cleanup_region; - } - - if (signature == 0x06) /* OPL2 */ - { - detected_model = 2; - } - else if (signature == 0x00 || signature == 0x0f) /* OPL3 or OPL4 */ - { - unsigned char tmp; - - detected_model = 3; - - /* - * Detect availability of OPL4 (_experimental_). Works probably - * only after a cold boot. In addition the OPL4 port - * of the chip may not be connected to the PC bus at all. - */ - - opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00); - opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); - - if ((tmp = inb(ioaddr)) == 0x02) /* Have a OPL4 */ - { - detected_model = 4; - } - - if (request_region(ioaddr - 8, 2, "OPL4")) /* OPL4 port was free */ - { - int tmp; - - outb((0x02), ioaddr - 8); /* Select OPL4 ID register */ - udelay(10); - tmp = inb(ioaddr - 7); /* Read it */ - udelay(10); - - if (tmp == 0x20) /* OPL4 should return 0x20 here */ - { - detected_model = 4; - outb((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ - udelay(10); - outb((0x1B), ioaddr - 7); /* Write value */ - udelay(10); - } - else - { /* release OPL4 port */ - release_region(ioaddr - 8, 2); - detected_model = 3; - } - } - opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); - } - for (i = 0; i < 9; i++) - opl3_command(ioaddr, KEYON_BLOCK + i, 0); /* - * Note off - */ - - opl3_command(ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl3_command(ioaddr, PERCOSSION_REGISTER, 0x00); /* - * Melodic mode. - */ - return 1; -cleanup_region: - release_region(ioaddr, 4); -cleanup_devc: - kfree(devc); - devc = NULL; - return 0; -} - -static int opl3_kill_note (int devno, int voice, int note, int velocity) -{ - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return 0; - - devc->v_alloc->map[voice] = 0; - - map = &pv_map[devc->lv_map[voice]]; - - if (map->voice_mode == 0) - return 0; - - opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20); - devc->voc[voice].keyon_byte = 0; - devc->voc[voice].bender = 0; - devc->voc[voice].volume = 64; - devc->voc[voice].panning = 0xffff; /* Not set */ - devc->voc[voice].bender_range = 200; - devc->voc[voice].orig_freq = 0; - devc->voc[voice].current_freq = 0; - devc->voc[voice].mode = 0; - return 0; -} - -#define HIHAT 0 -#define CYMBAL 1 -#define TOMTOM 2 -#define SNARE 3 -#define BDRUM 4 -#define UNDEFINED TOMTOM -#define DEFAULT TOMTOM - -static int store_instr(int instr_no, struct sbi_instrument *instr) -{ - if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || devc->model != 2)) - printk(KERN_WARNING "FM warning: Invalid patch format field (key) 0x%x\n", instr->key); - memcpy((char *) &(devc->i_map[instr_no]), (char *) instr, sizeof(*instr)); - return 0; -} - -static int opl3_set_instr (int dev, int voice, int instr_no) -{ - if (voice < 0 || voice >= devc->nr_voice) - return 0; - if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) - instr_no = 0; /* Acoustic piano (usually) */ - - devc->act_i[voice] = &devc->i_map[instr_no]; - return 0; -} - -/* - * The next table looks magical, but it certainly is not. Its values have - * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception - * for i=0. This log-table converts a linear volume-scaling (0..127) to a - * logarithmic scaling as present in the FM-synthesizer chips. so : Volume - * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative - * volume -8 it was implemented as a table because it is only 128 bytes and - * it saves a lot of log() calculations. (RH) - */ - -static char fm_volume_table[128] = -{ - -64, -48, -40, -35, -32, -29, -27, -26, - -24, -23, -21, -20, -19, -18, -18, -17, - -16, -15, -15, -14, -13, -13, -12, -12, - -11, -11, -10, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -6, -6, -6, - -5, -5, -5, -5, -4, -4, -4, -4, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -1, -1, -1, -1, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 4, - 4, 4, 4, 4, 4, 4, 4, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 8, 8, 8, 8, 8 -}; - -static void calc_vol(unsigned char *regbyte, int volume, int main_vol) -{ - int level = (~*regbyte & 0x3f); - - if (main_vol > 127) - main_vol = 127; - volume = (volume * main_vol) / 127; - - if (level) - level += fm_volume_table[volume]; - - if (level > 0x3f) - level = 0x3f; - if (level < 0) - level = 0; - - *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); -} - -static void set_voice_volume(int voice, int volume, int main_vol) -{ - unsigned char vol1, vol2, vol3, vol4; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return; - - map = &pv_map[devc->lv_map[voice]]; - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[0]; - - if (instr->channel < 0) - return; - - if (devc->voc[voice].mode == 0) - return; - - if (devc->voc[voice].mode == 2) - { - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - if ((instr->operators[10] & 0x01)) - { - calc_vol(&vol1, volume, main_vol); - calc_vol(&vol2, volume, main_vol); - } - else - { - calc_vol(&vol2, volume, main_vol); - } - opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); - } - else - { /* - * 4 OP voice - */ - int connection; - - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - vol3 = instr->operators[OFFS_4OP + 2]; - vol4 = instr->operators[OFFS_4OP + 3]; - - /* - * The connection method for 4 OP devc->voc is defined by the rightmost - * bits at the offsets 10 and 10+OFFS_4OP - */ - - connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - - switch (connection) - { - case 0: - calc_vol(&vol4, volume, main_vol); - break; - - case 1: - calc_vol(&vol2, volume, main_vol); - calc_vol(&vol4, volume, main_vol); - break; - - case 2: - calc_vol(&vol1, volume, main_vol); - calc_vol(&vol4, volume, main_vol); - break; - - case 3: - calc_vol(&vol1, volume, main_vol); - calc_vol(&vol3, volume, main_vol); - calc_vol(&vol4, volume, main_vol); - break; - - default: - ; - } - opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); - opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], vol3); - opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], vol4); - } -} - -static int opl3_start_note (int dev, int voice, int note, int volume) -{ - unsigned char data, fpc; - int block, fnum, freq, voice_mode, pan; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return 0; - - map = &pv_map[devc->lv_map[voice]]; - pan = devc->voc[voice].panning; - - if (map->voice_mode == 0) - return 0; - - if (note == 255) /* - * Just change the volume - */ - { - set_voice_volume(voice, volume, devc->voc[voice].volume); - return 0; - } - - /* - * Kill previous note before playing - */ - - opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* - * Carrier - * volume to - * min - */ - opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* - * Modulator - * volume to - */ - - if (map->voice_mode == 4) - { - opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], 0xff); - opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], 0xff); - } - - opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* - * Note - * off - */ - - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[0]; - - if (instr->channel < 0) - { - printk(KERN_WARNING "opl3: Initializing voice %d with undefined instrument\n", voice); - return 0; - } - - if (map->voice_mode == 2 && instr->key == OPL3_PATCH) - return 0; /* - * Cannot play - */ - - voice_mode = map->voice_mode; - - if (voice_mode == 4) - { - int voice_shift; - - voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; - voice_shift += map->voice_num; - - if (instr->key != OPL3_PATCH) /* - * Just 2 OP patch - */ - { - voice_mode = 2; - devc->cmask &= ~(1 << voice_shift); - } - else - { - devc->cmask |= (1 << voice_shift); - } - - opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - } - - /* - * Set Sound Characteristics - */ - - opl3_command(map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); - opl3_command(map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); - - /* - * Set Attack/Decay - */ - - opl3_command(map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); - opl3_command(map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); - - /* - * Set Sustain/Release - */ - - opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); - opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); - - /* - * Set Wave Select - */ - - opl3_command(map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); - opl3_command(map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); - - /* - * Set Feedback/Connection - */ - - fpc = instr->operators[10]; - - if (pan != 0xffff) - { - fpc &= ~STEREO_BITS; - if (pan < -64) - fpc |= VOICE_TO_LEFT; - else - if (pan > 64) - fpc |= VOICE_TO_RIGHT; - else - fpc |= (VOICE_TO_LEFT | VOICE_TO_RIGHT); - } - - if (!(fpc & 0x30)) - fpc |= 0x30; /* - * Ensure that at least one chn is enabled - */ - opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc); - - /* - * If the voice is a 4 OP one, initialize the operators 3 and 4 also - */ - - if (voice_mode == 4) - { - /* - * Set Sound Characteristics - */ - - opl3_command(map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); - opl3_command(map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); - - /* - * Set Attack/Decay - */ - - opl3_command(map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); - opl3_command(map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); - - /* - * Set Sustain/Release - */ - - opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); - opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); - - /* - * Set Wave Select - */ - - opl3_command(map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); - opl3_command(map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); - - /* - * Set Feedback/Connection - */ - - fpc = instr->operators[OFFS_4OP + 10]; - if (!(fpc & 0x30)) - fpc |= 0x30; /* - * Ensure that at least one chn is enabled - */ - opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); - } - - devc->voc[voice].mode = voice_mode; - set_voice_volume(voice, volume, devc->voc[voice].volume); - - freq = devc->voc[voice].orig_freq = note_to_freq(note) / 1000; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); - devc->voc[voice].current_freq = freq; - - freq_to_fnum(freq, &block, &fnum); - - /* - * Play note - */ - - data = fnum & 0xff; /* - * Least significant bits of fnumber - */ - opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; - opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); - if (voice_mode == 4) - opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); - - return 0; -} - -static void freq_to_fnum (int freq, int *block, int *fnum) -{ - int f, octave; - - /* - * Converts the note frequency to block and fnum values for the FM chip - */ - /* - * First try to compute the block -value (octave) where the note belongs - */ - - f = freq; - - octave = 5; - - if (f == 0) - octave = 0; - else if (f < 261) - { - while (f < 261) - { - octave--; - f <<= 1; - } - } - else if (f > 493) - { - while (f > 493) - { - octave++; - f >>= 1; - } - } - - if (octave > 7) - octave = 7; - - *fnum = freq * (1 << (20 - octave)) / 49716; - *block = octave; -} - -static void opl3_command (int io_addr, unsigned int addr, unsigned int val) -{ - int i; - - /* - * The original 2-OP synth requires a quite long delay after writing to a - * register. The OPL-3 survives with just two INBs - */ - - outb(((unsigned char) (addr & 0xff)), io_addr); - - if (devc->model != 2) - udelay(10); - else - for (i = 0; i < 2; i++) - inb(io_addr); - - outb(((unsigned char) (val & 0xff)), io_addr + 1); - - if (devc->model != 2) - udelay(30); - else - for (i = 0; i < 2; i++) - inb(io_addr); -} - -static void opl3_reset(int devno) -{ - int i; - - for (i = 0; i < 18; i++) - devc->lv_map[i] = i; - - for (i = 0; i < devc->nr_voice; i++) - { - opl3_command(pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); - - opl3_command(pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); - - if (pv_map[devc->lv_map[i]].voice_mode == 4) - { - opl3_command(pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); - - opl3_command(pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); - } - - opl3_kill_note(devno, i, 0, 64); - } - - if (devc->model == 2) - { - devc->v_alloc->max_voice = devc->nr_voice = 18; - - for (i = 0; i < 18; i++) - pv_map[i].voice_mode = 2; - - } -} - -static int opl3_open(int dev, int mode) -{ - int i; - - if (devc->busy) - return -EBUSY; - devc->busy = 1; - - devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; - devc->v_alloc->timestamp = 0; - - for (i = 0; i < 18; i++) - { - devc->v_alloc->map[i] = 0; - devc->v_alloc->alloc_times[i] = 0; - } - - devc->cmask = 0x00; /* - * Just 2 OP mode - */ - if (devc->model == 2) - opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - return 0; -} - -static void opl3_close(int dev) -{ - devc->busy = 0; - devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; - - devc->fm_info.nr_drums = 0; - devc->fm_info.perc_mode = 0; - - opl3_reset(dev); -} - -static void opl3_hw_control(int dev, unsigned char *event) -{ -} - -static int opl3_load_patch(int dev, int format, const char __user *addr, - int count, int pmgr_flag) -{ - struct sbi_instrument ins; - - if (count <sizeof(ins)) - { - printk(KERN_WARNING "FM Error: Patch record too short\n"); - return -EINVAL; - } - - if (copy_from_user(&ins, addr, sizeof(ins))) - return -EFAULT; - - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) - { - printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - ins.key = format; - - return store_instr(ins.channel, &ins); -} - -static void opl3_panning(int dev, int voice, int value) -{ - - if (voice < 0 || voice >= devc->nr_voice) - return; - - devc->voc[voice].panning = value; -} - -static void opl3_volume_method(int dev, int mode) -{ -} - -#define SET_VIBRATO(cell) { \ - tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ - if (pressure > 110) \ - tmp |= 0x40; /* Vibrato on */ \ - opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} - -static void opl3_aftertouch(int dev, int voice, int pressure) -{ - int tmp; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return; - - map = &pv_map[devc->lv_map[voice]]; - - if (map->voice_mode == 0) - return; - - /* - * Adjust the amount of vibrato depending the pressure - */ - - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[0]; - - if (devc->voc[voice].mode == 4) - { - int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - - switch (connection) - { - case 0: - SET_VIBRATO(4); - break; - - case 1: - SET_VIBRATO(2); - SET_VIBRATO(4); - break; - - case 2: - SET_VIBRATO(1); - SET_VIBRATO(4); - break; - - case 3: - SET_VIBRATO(1); - SET_VIBRATO(3); - SET_VIBRATO(4); - break; - - } - /* - * Not implemented yet - */ - } - else - { - SET_VIBRATO(1); - - if ((instr->operators[10] & 0x01)) /* - * Additive synthesis - */ - SET_VIBRATO(2); - } -} - -#undef SET_VIBRATO - -static void bend_pitch(int dev, int voice, int value) -{ - unsigned char data; - int block, fnum, freq; - struct physical_voice_info *map; - - map = &pv_map[devc->lv_map[voice]]; - - if (map->voice_mode == 0) - return; - - devc->voc[voice].bender = value; - if (!value) - return; - if (!(devc->voc[voice].keyon_byte & 0x20)) - return; /* - * Not keyed on - */ - - freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); - devc->voc[voice].current_freq = freq; - - freq_to_fnum(freq, &block, &fnum); - - data = fnum & 0xff; /* - * Least significant bits of fnumber - */ - opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; - opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); -} - -static void opl3_controller (int dev, int voice, int ctrl_num, int value) -{ - if (voice < 0 || voice >= devc->nr_voice) - return; - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - bend_pitch(dev, voice, value); - break; - - case CTRL_PITCH_BENDER_RANGE: - devc->voc[voice].bender_range = value; - break; - - case CTL_MAIN_VOLUME: - devc->voc[voice].volume = value / 128; - break; - - case CTL_PAN: - devc->voc[voice].panning = (value * 2) - 128; - break; - } -} - -static void opl3_bender(int dev, int voice, int value) -{ - if (voice < 0 || voice >= devc->nr_voice) - return; - - bend_pitch(dev, voice, value - 8192); -} - -static int opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) -{ - int i, p, best, first, avail, best_time = 0x7fffffff; - struct sbi_instrument *instr; - int is4op; - int instr_no; - - if (chn < 0 || chn > 15) - instr_no = 0; - else - instr_no = devc->chn_info[chn].pgm_num; - - instr = &devc->i_map[instr_no]; - if (instr->channel < 0 || /* Instrument not loaded */ - devc->nr_voice != 12) /* Not in 4 OP mode */ - is4op = 0; - else if (devc->nr_voice == 12) /* 4 OP mode */ - is4op = (instr->key == OPL3_PATCH); - else - is4op = 0; - - if (is4op) - { - first = p = 0; - avail = 6; - } - else - { - if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP only' operators first */ - first = p = 6; - else - first = p = 0; - avail = devc->nr_voice; - } - - /* - * Now try to find a free voice - */ - best = first; - - for (i = 0; i < avail; i++) - { - if (alloc->map[p] == 0) - { - return p; - } - if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ - { - best_time = alloc->alloc_times[p]; - best = p; - } - p = (p + 1) % avail; - } - - /* - * Insert some kind of priority mechanism here. - */ - - if (best < 0) - best = 0; - if (best > devc->nr_voice) - best -= devc->nr_voice; - - return best; /* All devc->voc in use. Select the first one. */ -} - -static void opl3_setup_voice(int dev, int voice, int chn) -{ - struct channel_info *info; - - if (voice < 0 || voice >= devc->nr_voice) - return; - - if (chn < 0 || chn > 15) - return; - - info = &synth_devs[dev]->chn_info[chn]; - - opl3_set_instr(dev, voice, info->pgm_num); - - devc->voc[voice].bender = 0; - devc->voc[voice].bender_range = info->bender_range; - devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; - devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; -} - -static struct synth_operations opl3_operations = -{ - .owner = THIS_MODULE, - .id = "OPL", - .info = NULL, - .midi_dev = 0, - .synth_type = SYNTH_TYPE_FM, - .synth_subtype = FM_TYPE_ADLIB, - .open = opl3_open, - .close = opl3_close, - .ioctl = opl3_ioctl, - .kill_note = opl3_kill_note, - .start_note = opl3_start_note, - .set_instr = opl3_set_instr, - .reset = opl3_reset, - .hw_control = opl3_hw_control, - .load_patch = opl3_load_patch, - .aftertouch = opl3_aftertouch, - .controller = opl3_controller, - .panning = opl3_panning, - .volume_method = opl3_volume_method, - .bender = opl3_bender, - .alloc_voice = opl3_alloc_voice, - .setup_voice = opl3_setup_voice -}; - -static int opl3_init(int ioaddr, struct module *owner) -{ - int i; - int me; - - if (devc == NULL) - { - printk(KERN_ERR "opl3: Device control structure not initialized.\n"); - return -1; - } - - if ((me = sound_alloc_synthdev()) == -1) - { - printk(KERN_WARNING "opl3: Too many synthesizers\n"); - return -1; - } - - devc->nr_voice = 9; - - devc->fm_info.device = 0; - devc->fm_info.synth_type = SYNTH_TYPE_FM; - devc->fm_info.synth_subtype = FM_TYPE_ADLIB; - devc->fm_info.perc_mode = 0; - devc->fm_info.nr_voices = 9; - devc->fm_info.nr_drums = 0; - devc->fm_info.instr_bank_size = SBFM_MAXINSTR; - devc->fm_info.capabilities = 0; - devc->left_io = ioaddr; - devc->right_io = ioaddr + 2; - - if (detected_model <= 2) - devc->model = 1; - else - { - devc->model = 2; - if (detected_model == 4) - devc->is_opl4 = 1; - } - - opl3_operations.info = &devc->fm_info; - - synth_devs[me] = &opl3_operations; - - if (owner) - synth_devs[me]->owner = owner; - - sequencer_init(); - devc->v_alloc = &opl3_operations.alloc; - devc->chn_info = &opl3_operations.chn_info[0]; - - if (devc->model == 2) - { - if (devc->is_opl4) - strcpy(devc->fm_info.name, "Yamaha OPL4/OPL3 FM"); - else - strcpy(devc->fm_info.name, "Yamaha OPL3"); - - devc->v_alloc->max_voice = devc->nr_voice = 18; - devc->fm_info.nr_drums = 0; - devc->fm_info.synth_subtype = FM_TYPE_OPL3; - devc->fm_info.capabilities |= SYNTH_CAP_OPL3; - - for (i = 0; i < 18; i++) - { - if (pv_map[i].ioaddr == USE_LEFT) - pv_map[i].ioaddr = devc->left_io; - else - pv_map[i].ioaddr = devc->right_io; - } - opl3_command(devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE); - opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x00); - } - else - { - strcpy(devc->fm_info.name, "Yamaha OPL2"); - devc->v_alloc->max_voice = devc->nr_voice = 9; - devc->fm_info.nr_drums = 0; - - for (i = 0; i < 18; i++) - pv_map[i].ioaddr = devc->left_io; - } - conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1); - - for (i = 0; i < SBFM_MAXINSTR; i++) - devc->i_map[i].channel = -1; - - return me; -} - -static int me; - -static int io = -1; - -module_param_hw(io, int, ioport, 0); - -static int __init init_opl3 (void) -{ - printk(KERN_INFO "YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); - - if (io != -1) /* User loading pure OPL3 module */ - { - if (!opl3_detect(io)) - { - return -ENODEV; - } - - me = opl3_init(io, THIS_MODULE); - } - - return 0; -} - -static void __exit cleanup_opl3(void) -{ - if (devc && io != -1) - { - if (devc->base) { - release_region(devc->base,4); - if (devc->is_opl4) - release_region(devc->base - 8, 2); - } - kfree(devc); - devc = NULL; - sound_unload_synthdev(me); - } -} - -module_init(init_opl3); -module_exit(cleanup_opl3); - -#ifndef MODULE -static int __init setup_opl3(char *str) -{ - /* io */ - int ints[2]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - - return 1; -} - -__setup("opl3=", setup_opl3); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/opl3_hw.h b/sound/oss/opl3_hw.h deleted file mode 100644 index 8b11c893e869..000000000000 --- a/sound/oss/opl3_hw.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * opl3_hw.h - Definitions of the OPL-3 registers - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * The OPL-3 mode is switched on by writing 0x01, to the offset 5 - * of the right side. - * - * Another special register at the right side is at offset 4. It contains - * a bit mask defining which voices are used as 4 OP voices. - * - * The percussive mode is implemented in the left side only. - * - * With the above exceptions the both sides can be operated independently. - * - * A 4 OP voice can be created by setting the corresponding - * bit at offset 4 of the right side. - * - * For example setting the rightmost bit (0x01) changes the - * first voice on the right side to the 4 OP mode. The fourth - * voice is made inaccessible. - * - * If a voice is set to the 2 OP mode, it works like 2 OP modes - * of the original YM3812 (AdLib). In addition the voice can - * be connected the left, right or both stereo channels. It can - * even be left unconnected. This works with 4 OP voices also. - * - * The stereo connection bits are located in the FEEDBACK_CONNECTION - * register of the voice (0xC0-0xC8). In 4 OP voices these bits are - * in the second half of the voice. - */ - -/* - * Register numbers for the global registers - */ - -#define TEST_REGISTER 0x01 -#define ENABLE_WAVE_SELECT 0x20 - -#define TIMER1_REGISTER 0x02 -#define TIMER2_REGISTER 0x03 -#define TIMER_CONTROL_REGISTER 0x04 /* Left side */ -#define IRQ_RESET 0x80 -#define TIMER1_MASK 0x40 -#define TIMER2_MASK 0x20 -#define TIMER1_START 0x01 -#define TIMER2_START 0x02 - -#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */ -#define RIGHT_4OP_0 0x01 -#define RIGHT_4OP_1 0x02 -#define RIGHT_4OP_2 0x04 -#define LEFT_4OP_0 0x08 -#define LEFT_4OP_1 0x10 -#define LEFT_4OP_2 0x20 - -#define OPL3_MODE_REGISTER 0x05 /* Right side */ -#define OPL3_ENABLE 0x01 -#define OPL4_ENABLE 0x02 - -#define KBD_SPLIT_REGISTER 0x08 /* Left side */ -#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ -#define KEYBOARD_SPLIT 0x40 - -#define PERCOSSION_REGISTER 0xbd /* Left side only */ -#define TREMOLO_DEPTH 0x80 -#define VIBRATO_DEPTH 0x40 -#define PERCOSSION_ENABLE 0x20 -#define BASSDRUM_ON 0x10 -#define SNAREDRUM_ON 0x08 -#define TOMTOM_ON 0x04 -#define CYMBAL_ON 0x02 -#define HIHAT_ON 0x01 - -/* - * Offsets to the register banks for operators. To get the - * register number just add the operator offset to the bank offset - * - * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) - */ -#define AM_VIB 0x20 -#define TREMOLO_ON 0x80 -#define VIBRATO_ON 0x40 -#define SUSTAIN_ON 0x20 -#define KSR 0x10 /* Key scaling rate */ -#define MULTIPLE_MASK 0x0f /* Frequency multiplier */ - - /* - * KSL/Total level (0x40 to 0x55) - */ -#define KSL_LEVEL 0x40 -#define KSL_MASK 0xc0 /* Envelope scaling bits */ -#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ - -/* - * Attack / Decay rate (0x60 to 0x75) - */ -#define ATTACK_DECAY 0x60 -#define ATTACK_MASK 0xf0 -#define DECAY_MASK 0x0f - -/* - * Sustain level / Release rate (0x80 to 0x95) - */ -#define SUSTAIN_RELEASE 0x80 -#define SUSTAIN_MASK 0xf0 -#define RELEASE_MASK 0x0f - -/* - * Wave select (0xE0 to 0xF5) - */ -#define WAVE_SELECT 0xe0 - -/* - * Offsets to the register banks for voices. Just add to the - * voice number to get the register number. - * - * F-Number low bits (0xA0 to 0xA8). - */ -#define FNUM_LOW 0xa0 - -/* - * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) - */ -#define KEYON_BLOCK 0xb0 -#define KEYON_BIT 0x20 -#define BLOCKNUM_MASK 0x1c -#define FNUM_HIGH_MASK 0x03 - -/* - * Feedback / Connection (0xc0 to 0xc8) - * - * These registers have two new bits when the OPL-3 mode - * is selected. These bits controls connecting the voice - * to the stereo channels. For 4 OP voices this bit is - * defined in the second half of the voice (add 3 to the - * register offset). - * - * For 4 OP voices the connection bit is used in the - * both halves (gives 4 ways to connect the operators). - */ -#define FEEDBACK_CONNECTION 0xc0 -#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ -#define CONNECTION_BIT 0x01 -/* - * In the 4 OP mode there is four possible configurations how the - * operators can be connected together (in 2 OP modes there is just - * AM or FM). The 4 OP connection mode is defined by the rightmost - * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves. - * - * First half Second half Mode - * - * +---+ - * v | - * 0 0 >+-1-+--2--3--4--> - * - * - * - * +---+ - * | | - * 0 1 >+-1-+--2-+ - * |-> - * >--3----4-+ - * - * +---+ - * | | - * 1 0 >+-1-+-----+ - * |-> - * >--2--3--4-+ - * - * +---+ - * | | - * 1 1 >+-1-+--+ - * | - * >--2--3-+-> - * | - * >--4----+ - */ -#define STEREO_BITS 0x30 /* OPL-3 only */ -#define VOICE_TO_LEFT 0x10 -#define VOICE_TO_RIGHT 0x20 - -/* - * Definition table for the physical voices - */ - -struct physical_voice_info { - unsigned char voice_num; - unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ - unsigned short ioaddr; /* I/O port (left or right side) */ - unsigned char op[4]; /* Operator offsets */ - }; - -/* - * There is 18 possible 2 OP voices - * (9 in the left and 9 in the right). - * The first OP is the modulator and 2nd is the carrier. - * - * The first three voices in the both sides may be connected - * with another voice to a 4 OP voice. For example voice 0 - * can be connected with voice 3. The operators of voice 3 are - * used as operators 3 and 4 of the new 4 OP voice. - * In this case the 2 OP voice number 0 is the 'first half' and - * voice 3 is the second. - */ - -#define USE_LEFT 0 -#define USE_RIGHT 1 - -static struct physical_voice_info pv_map[18] = -{ -/* No Mode Side OP1 OP2 OP3 OP4 */ -/* --------------------------------------------------- */ - { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */ - { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */ - { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */ - - { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}}, - { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}}, - { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}} -}; -/* - * DMA buffer calls - */ diff --git a/sound/oss/os.h b/sound/oss/os.h deleted file mode 100644 index 16f3a069b85c..000000000000 --- a/sound/oss/os.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define ALLOW_SELECT -#undef NO_INLINE_ASM -#define SHORT_BANNERS -#define MANUAL_PNP -#undef DO_TIMINGS - -#include <linux/module.h> - -#ifdef __KERNEL__ -#include <linux/string.h> -#include <linux/fs.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/param.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <asm/page.h> -#include <linux/vmalloc.h> -#include <linux/uaccess.h> -#include <linux/poll.h> -#include <linux/pci.h> -#endif - -#include <linux/soundcard.h> - -#define FALSE 0 -#define TRUE 1 - -extern int sound_alloc_dma(int chn, char *deviceID); -extern int sound_open_dma(int chn, char *deviceID); -extern void sound_free_dma(int chn); -extern void sound_close_dma(int chn); - -extern void reprogram_timer(void); - -#define USE_AUTOINIT_DMA - -extern void *sound_mem_blocks[1024]; -extern int sound_nblocks; - -#undef PSEUDO_DMA_AUTOINIT -#define ALLOW_BUFFER_MAPPING - -extern const struct file_operations oss_sound_fops; diff --git a/sound/oss/pas2.h b/sound/oss/pas2.h deleted file mode 100644 index 57f476238309..000000000000 --- a/sound/oss/pas2.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* From pas_card.c */ -int pas_set_intr(int mask); -int pas_remove_intr(int mask); -unsigned char pas_read(int ioaddr); -void pas_write(unsigned char data, int ioaddr); - -/* From pas_audio.c */ -void pas_pcm_interrupt(unsigned char status, int cause); -void pas_pcm_init(struct address_info *hw_config); - -/* From pas_mixer.c */ -int pas_init_mixer(void); - -/* From pas_midi.c */ -void pas_midi_init(void); -void pas_midi_interrupt(void); - -/* From pas2_mixer.c*/ -void mix_write(unsigned char data, int ioaddr); diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c deleted file mode 100644 index 769fca692d2a..000000000000 --- a/sound/oss/pas2_card.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * sound/oss/pas2_card.c - * - * Detection routine for the Pro Audio Spectrum cards. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "pas2.h" -#include "sb.h" - -static unsigned char dma_bits[] = { - 4, 1, 2, 3, 0, 5, 6, 7 -}; - -static unsigned char irq_bits[] = { - 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 -}; - -static unsigned char sb_irq_bits[] = { - 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, - 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 -}; - -static unsigned char sb_dma_bits[] = { - 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 -}; - -/* - * The Address Translation code is used to convert I/O register addresses to - * be relative to the given base -register - */ - -int pas_translate_code = 0; -static int pas_intr_mask; -static int pas_irq; -static int pas_sb_base; -DEFINE_SPINLOCK(pas_lock); -#ifndef CONFIG_PAS_JOYSTICK -static bool joystick; -#else -static bool joystick = 1; -#endif -#ifdef SYMPHONY_PAS -static bool symphony = 1; -#else -static bool symphony; -#endif -#ifdef BROKEN_BUS_CLOCK -static bool broken_bus_clock = 1; -#else -static bool broken_bus_clock; -#endif - -static struct address_info cfg; -static struct address_info cfg2; - -char pas_model = 0; -static char *pas_model_names[] = { - "", - "Pro AudioSpectrum+", - "CDPC", - "Pro AudioSpectrum 16", - "Pro AudioSpectrum 16D" -}; - -/* - * pas_read() and pas_write() are equivalents of inb and outb - * These routines perform the I/O address translation required - * to support other than the default base address - */ - -unsigned char pas_read(int ioaddr) -{ - return inb(ioaddr + pas_translate_code); -} - -void pas_write(unsigned char data, int ioaddr) -{ - outb((data), ioaddr + pas_translate_code); -} - -/******************* Begin of the Interrupt Handler ********************/ - -static irqreturn_t pasintr(int irq, void *dev_id) -{ - int status; - - status = pas_read(0x0B89); - pas_write(status, 0x0B89); /* Clear interrupt */ - - if (status & 0x08) - { - pas_pcm_interrupt(status, 1); - status &= ~0x08; - } - if (status & 0x10) - { - pas_midi_interrupt(); - status &= ~0x10; - } - return IRQ_HANDLED; -} - -int pas_set_intr(int mask) -{ - if (!mask) - return 0; - - pas_intr_mask |= mask; - - pas_write(pas_intr_mask, 0x0B8B); - return 0; -} - -int pas_remove_intr(int mask) -{ - if (!mask) - return 0; - - pas_intr_mask &= ~mask; - pas_write(pas_intr_mask, 0x0B8B); - - return 0; -} - -/******************* End of the Interrupt handler **********************/ - -/******************* Begin of the Initialization Code ******************/ - -static int __init config_pas_hw(struct address_info *hw_config) -{ - char ok = 1; - unsigned int_ptrs; /* scsi/sound interrupt pointers */ - - pas_irq = hw_config->irq; - - pas_write(0x00, 0x0B8B); - pas_write(0x36, 0x138B); - pas_write(0x36, 0x1388); - pas_write(0, 0x1388); - pas_write(0x74, 0x138B); - pas_write(0x74, 0x1389); - pas_write(0, 0x1389); - - pas_write(0x80 | 0x40 | 0x20 | 1, 0x0B8A); - pas_write(0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); - pas_write(0x01 | 0x02 | 0x04 | 0x10 /* - * | - * 0x80 - */ , 0xB88); - - pas_write(0x80 | (joystick ? 0x40 : 0), 0xF388); - - if (pas_irq < 0 || pas_irq > 15) - { - printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); - hw_config->irq=-1; - ok = 0; - } - else - { - int_ptrs = pas_read(0xF38A); - int_ptrs = (int_ptrs & 0xf0) | irq_bits[pas_irq]; - pas_write(int_ptrs, 0xF38A); - if (!irq_bits[pas_irq]) - { - printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); - hw_config->irq=-1; - ok = 0; - } - else - { - if (request_irq(pas_irq, pasintr, 0, "PAS16",hw_config) < 0) { - printk(KERN_ERR "PAS16: Cannot allocate IRQ %d\n",pas_irq); - hw_config->irq=-1; - ok = 0; - } - } - } - - if (hw_config->dma < 0 || hw_config->dma > 7) - { - printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); - hw_config->dma=-1; - ok = 0; - } - else - { - pas_write(dma_bits[hw_config->dma], 0xF389); - if (!dma_bits[hw_config->dma]) - { - printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); - hw_config->dma=-1; - ok = 0; - } - else - { - if (sound_alloc_dma(hw_config->dma, "PAS16")) - { - printk(KERN_ERR "pas2_card.c: Can't allocate DMA channel\n"); - hw_config->dma=-1; - ok = 0; - } - } - } - - /* - * This fixes the timing problems of the PAS due to the Symphony chipset - * as per Media Vision. Only define this if your PAS doesn't work correctly. - */ - - if(symphony) - { - outb((0x05), 0xa8); - outb((0x60), 0xa9); - } - - if(broken_bus_clock) - pas_write(0x01 | 0x10 | 0x20 | 0x04, 0x8388); - else - /* - * pas_write(0x01, 0x8388); - */ - pas_write(0x01 | 0x10 | 0x20, 0x8388); - - pas_write(0x18, 0x838A); /* ??? */ - pas_write(0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ - pas_write(8, 0xBF8A); - - mix_write(0x80 | 5, 0x078B); - mix_write(5, 0x078B); - - { - struct address_info *sb_config; - - sb_config = &cfg2; - if (sb_config->io_base) - { - unsigned char irq_dma; - - /* - * Turn on Sound Blaster compatibility - * bit 1 = SB emulation - * bit 0 = MPU401 emulation (CDPC only :-( ) - */ - - pas_write(0x02, 0xF788); - - /* - * "Emulation address" - */ - - pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); - pas_sb_base = sb_config->io_base; - - if (!sb_dma_bits[sb_config->dma]) - printk(KERN_ERR "PAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); - - if (!sb_irq_bits[sb_config->irq]) - printk(KERN_ERR "PAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); - - irq_dma = sb_dma_bits[sb_config->dma] | - sb_irq_bits[sb_config->irq]; - - pas_write(irq_dma, 0xFB8A); - } - else - pas_write(0x00, 0xF788); - } - - if (!ok) - printk(KERN_WARNING "PAS16: Driver not enabled\n"); - - return ok; -} - -static int __init detect_pas_hw(struct address_info *hw_config) -{ - unsigned char board_id, foo; - - /* - * WARNING: Setting an option like W:1 or so that disables warm boot reset - * of the card will screw up this detect code something fierce. Adding code - * to handle this means possibly interfering with other cards on the bus if - * you have something on base port 0x388. SO be forewarned. - */ - - outb((0xBC), 0x9A01); /* Activate first board */ - outb((hw_config->io_base >> 2), 0x9A01); /* Set base address */ - pas_translate_code = hw_config->io_base - 0x388; - pas_write(1, 0xBF88); /* Select one wait states */ - - board_id = pas_read(0x0B8B); - - if (board_id == 0xff) - return 0; - - /* - * We probably have a PAS-series board, now check for a PAS16-series board - * by trying to change the board revision bits. PAS16-series hardware won't - * let you do this - the bits are read-only. - */ - - foo = board_id ^ 0xe0; - - pas_write(foo, 0x0B8B); - foo = pas_read(0x0B8B); - pas_write(board_id, 0x0B8B); - - if (board_id != foo) - return 0; - - pas_model = pas_read(0xFF88); - - return pas_model; -} - -static void __init attach_pas_card(struct address_info *hw_config) -{ - pas_irq = hw_config->irq; - - if (detect_pas_hw(hw_config)) - { - - if ((pas_model = pas_read(0xFF88))) - { - char temp[100]; - - if (pas_model < 0 || - pas_model >= ARRAY_SIZE(pas_model_names)) { - printk(KERN_ERR "pas2 unrecognized model.\n"); - return; - } - sprintf(temp, - "%s rev %d", pas_model_names[(int) pas_model], - pas_read(0x2789)); - conf_printf(temp, hw_config); - } - if (config_pas_hw(hw_config)) - { - pas_pcm_init(hw_config); - pas_midi_init(); - pas_init_mixer(); - } - } -} - -static inline int __init probe_pas(struct address_info *hw_config) -{ - return detect_pas_hw(hw_config); -} - -static void __exit unload_pas(struct address_info *hw_config) -{ - extern int pas_audiodev; - extern int pas2_mididev; - - if (hw_config->dma>0) - sound_free_dma(hw_config->dma); - if (hw_config->irq>0) - free_irq(hw_config->irq, hw_config); - - if(pas_audiodev!=-1) - sound_unload_mixerdev(audio_devs[pas_audiodev]->mixer_dev); - if(pas2_mididev!=-1) - sound_unload_mididev(pas2_mididev); - if(pas_audiodev!=-1) - sound_unload_audiodev(pas_audiodev); -} - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma16 = -1; /* Set this for modules that need it */ - -static int __initdata sb_io = 0; -static int __initdata sb_irq = -1; -static int __initdata sb_dma = -1; -static int __initdata sb_dma16 = -1; - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param_hw(dma, int, dma, 0); -module_param_hw(dma16, int, dma, 0); - -module_param_hw(sb_io, int, ioport, 0); -module_param_hw(sb_irq, int, irq, 0); -module_param_hw(sb_dma, int, dma, 0); -module_param_hw(sb_dma16, int, dma, 0); - -module_param(joystick, bool, 0); -module_param(symphony, bool, 0); -module_param(broken_bus_clock, bool, 0); - -MODULE_LICENSE("GPL"); - -static int __init init_pas2(void) -{ - printk(KERN_INFO "Pro Audio Spectrum driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma16; - - cfg2.io_base = sb_io; - cfg2.irq = sb_irq; - cfg2.dma = sb_dma; - cfg2.dma2 = sb_dma16; - - if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { - printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); - return -EINVAL; - } - - if (!probe_pas(&cfg)) - return -ENODEV; - attach_pas_card(&cfg); - - return 0; -} - -static void __exit cleanup_pas2(void) -{ - unload_pas(&cfg); -} - -module_init(init_pas2); -module_exit(cleanup_pas2); - -#ifndef MODULE -static int __init setup_pas2(char *str) -{ - /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, sb_dma2 */ - int ints[9]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma16 = ints[4]; - - sb_io = ints[5]; - sb_irq = ints[6]; - sb_dma = ints[7]; - sb_dma16 = ints[8]; - - return 1; -} - -__setup("pas2=", setup_pas2); -#endif diff --git a/sound/oss/pas2_midi.c b/sound/oss/pas2_midi.c deleted file mode 100644 index 1122d10a20c3..000000000000 --- a/sound/oss/pas2_midi.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * sound/oss/pas2_midi.c - * - * The low level driver for the PAS Midi Interface. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Bartlomiej Zolnierkiewicz : Added __init to pas_init_mixer() - */ - -#include <linux/init.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "pas2.h" - -extern spinlock_t pas_lock; - -static int midi_busy, input_opened; -static int my_dev; - -int pas2_mididev=-1; - -static unsigned char tmp_queue[256]; -static volatile int qlen; -static volatile unsigned char qhead, qtail; - -static void (*midi_input_intr) (int dev, unsigned char data); - -static int pas_midi_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - int err; - unsigned long flags; - unsigned char ctrl; - - - if (midi_busy) - return -EBUSY; - - /* - * Reset input and output FIFO pointers - */ - pas_write(0x20 | 0x40, - 0x178b); - - spin_lock_irqsave(&pas_lock, flags); - - if ((err = pas_set_intr(0x10)) < 0) - { - spin_unlock_irqrestore(&pas_lock, flags); - return err; - } - /* - * Enable input available and output FIFO empty interrupts - */ - - ctrl = 0; - input_opened = 0; - midi_input_intr = input; - - if (mode == OPEN_READ || mode == OPEN_READWRITE) - { - ctrl |= 0x04; /* Enable input */ - input_opened = 1; - } - if (mode == OPEN_WRITE || mode == OPEN_READWRITE) - { - ctrl |= 0x08 | 0x10; /* Enable output */ - } - pas_write(ctrl, 0x178b); - - /* - * Acknowledge any pending interrupts - */ - - pas_write(0xff, 0x1B88); - - spin_unlock_irqrestore(&pas_lock, flags); - - midi_busy = 1; - qlen = qhead = qtail = 0; - return 0; -} - -static void pas_midi_close(int dev) -{ - - /* - * Reset FIFO pointers, disable intrs - */ - pas_write(0x20 | 0x40, 0x178b); - - pas_remove_intr(0x10); - midi_busy = 0; -} - -static int dump_to_midi(unsigned char midi_byte) -{ - int fifo_space, x; - - fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f; - - /* - * The MIDI FIFO space register and it's documentation is nonunderstandable. - * There seem to be no way to differentiate between buffer full and buffer - * empty situations. For this reason we don't never write the buffer - * completely full. In this way we can assume that 0 (or is it 15) - * means that the buffer is empty. - */ - - if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */ - return 0; /* Ask upper layers to retry after some time */ - - pas_write(midi_byte, 0x178A); - - return 1; -} - -static int pas_midi_out(int dev, unsigned char midi_byte) -{ - - unsigned long flags; - - /* - * Drain the local queue first - */ - - spin_lock_irqsave(&pas_lock, flags); - - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - spin_unlock_irqrestore(&pas_lock, flags); - - /* - * Output the byte if the local queue is empty. - */ - - if (!qlen) - if (dump_to_midi(midi_byte)) - return 1; - - /* - * Put to the local queue - */ - - if (qlen >= 256) - return 0; /* Local queue full */ - - spin_lock_irqsave(&pas_lock, flags); - - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; - - spin_unlock_irqrestore(&pas_lock, flags); - - return 1; -} - -static int pas_midi_start_read(int dev) -{ - return 0; -} - -static int pas_midi_end_read(int dev) -{ - return 0; -} - -static void pas_midi_kick(int dev) -{ -} - -static int pas_buffer_status(int dev) -{ - return qlen; -} - -#define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations pas_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = pas_midi_open, - .close = pas_midi_close, - .outputc = pas_midi_out, - .start_read = pas_midi_start_read, - .end_read = pas_midi_end_read, - .kick = pas_midi_kick, - .buffer_status = pas_buffer_status, -}; - -void __init pas_midi_init(void) -{ - int dev = sound_alloc_mididev(); - - if (dev == -1) - { - printk(KERN_WARNING "pas_midi_init: Too many midi devices detected\n"); - return; - } - std_midi_synth.midi_dev = my_dev = dev; - midi_devs[dev] = &pas_midi_operations; - pas2_mididev = dev; - sequencer_init(); -} - -void pas_midi_interrupt(void) -{ - unsigned char stat; - int i, incount; - - stat = pas_read(0x1B88); - - if (stat & 0x04) /* Input data available */ - { - incount = pas_read(0x1B89) & 0x0f; /* Input FIFO size */ - if (!incount) - incount = 16; - - for (i = 0; i < incount; i++) - if (input_opened) - { - midi_input_intr(my_dev, pas_read(0x178A)); - } else - pas_read(0x178A); /* Flush */ - } - if (stat & (0x08 | 0x10)) - { - spin_lock(&pas_lock);/* called in irq context */ - - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - spin_unlock(&pas_lock); - } - if (stat & 0x40) - { - printk(KERN_WARNING "MIDI output overrun %x,%x\n", pas_read(0x1B89), stat); - } - pas_write(stat, 0x1B88); /* Acknowledge interrupts */ -} diff --git a/sound/oss/pas2_mixer.c b/sound/oss/pas2_mixer.c deleted file mode 100644 index 50b5bd501247..000000000000 --- a/sound/oss/pas2_mixer.c +++ /dev/null @@ -1,327 +0,0 @@ - -/* - * sound/oss/pas2_mixer.c - * - * Mixer routines for the Pro Audio Spectrum cards. - */ - -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Bartlomiej Zolnierkiewicz : added __init to pas_init_mixer() - */ -#include <linux/init.h> -#include "sound_config.h" - -#include "pas2.h" - -extern int pas_translate_code; -extern char pas_model; -extern int *pas_osp; -extern int pas_audiodev; - -static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ -static int mode_control; - -#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_ALTPCM) - -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV) - -static int *levels; - -static int default_levels[32] = -{ - 0x3232, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x5050, /* FM */ - 0x4b4b, /* PCM */ - 0x3232, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x4b4b, /* Mic */ - 0x4b4b, /* CD */ - 0x6464, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x6464 /* Recording level */ -}; - -void -mix_write(unsigned char data, int ioaddr) -{ - /* - * The Revision D cards have a problem with their MVA508 interface. The - * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and - * MSBs out of the output byte and to do a 16-bit out to the mixer port - - * 1. We need to do this because it isn't timing problem but chip access - * sequence problem. - */ - - if (pas_model == 4) - { - outw(data | (data << 8), (ioaddr + pas_translate_code) - 1); - outb((0x80), 0); - } else - pas_write(data, ioaddr); -} - -static int -mixer_output(int right_vol, int left_vol, int div, int bits, - int mixer) /* Input or output mixer */ -{ - int left = left_vol * div / 100; - int right = right_vol * div / 100; - - - if (bits & 0x10) - { - left |= mixer; - right |= mixer; - } - if (bits == 0x03 || bits == 0x04) - { - mix_write(0x80 | bits, 0x078B); - mix_write(left, 0x078B); - right_vol = left_vol; - } else - { - mix_write(0x80 | 0x20 | bits, 0x078B); - mix_write(left, 0x078B); - mix_write(0x80 | 0x40 | bits, 0x078B); - mix_write(right, 0x078B); - } - - return (left_vol | (right_vol << 8)); -} - -static void -set_mode(int new_mode) -{ - mix_write(0x80 | 0x05, 0x078B); - mix_write(new_mode, 0x078B); - - mode_control = new_mode; -} - -static int -pas_mixer_set(int whichDev, unsigned int level) -{ - int left, right, devmask, changed, i, mixer = 0; - - left = level & 0x7f; - right = (level & 0x7f00) >> 8; - - if (whichDev < SOUND_MIXER_NRDEVICES) { - if ((1 << whichDev) & rec_devices) - mixer = 0x20; - else - mixer = 0x00; - } - - switch (whichDev) - { - case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ - levels[whichDev] = mixer_output(right, left, 63, 0x01, 0); - break; - - /* - * Note! Bass and Treble are mono devices. Will use just the left - * channel. - */ - case SOUND_MIXER_BASS: /* Bass (0-12) */ - levels[whichDev] = mixer_output(right, left, 12, 0x03, 0); - break; - case SOUND_MIXER_TREBLE: /* Treble (0-12) */ - levels[whichDev] = mixer_output(right, left, 12, 0x04, 0); - break; - - case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x00, mixer); - break; - case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x05, mixer); - break; - case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x07, mixer); - break; - case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x06, mixer); - break; - case SOUND_MIXER_LINE: /* External line (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x02, mixer); - break; - case SOUND_MIXER_CD: /* CD (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x03, mixer); - break; - case SOUND_MIXER_MIC: /* External microphone (0-31) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x04, mixer); - break; - case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ - levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x01, - 0x00); - break; - case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ - levels[whichDev] = mixer_output(right, left, 15, 0x02, 0); - break; - - - case SOUND_MIXER_RECSRC: - devmask = level & POSSIBLE_RECORDING_DEVICES; - - changed = devmask ^ rec_devices; - rec_devices = devmask; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (changed & (1 << i)) - { - pas_mixer_set(i, levels[i]); - } - return rec_devices; - break; - - default: - return -EINVAL; - } - - return (levels[whichDev]); -} - -/*****/ - -static void -pas_mixer_reset(void) -{ - int foo; - - for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) - pas_mixer_set(foo, levels[foo]); - - set_mode(0x04 | 0x01); -} - -static int pas_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int level,v ; - int __user *p = (int __user *)arg; - - if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */ - if (get_user(level, p)) - return -EFAULT; - if (level == -1) /* Return current settings */ - level = (mode_control & 0x04); - else { - mode_control &= ~0x04; - if (level) - mode_control |= 0x04; - set_mode(mode_control); - } - level = !!level; - return put_user(level, p); - } - if (cmd == SOUND_MIXER_PRIVATE2) { /* Set enhance bit */ - if (get_user(level, p)) - return -EFAULT; - if (level == -1) { /* Return current settings */ - if (!(mode_control & 0x03)) - level = 0; - else - level = ((mode_control & 0x03) + 1) * 20; - } else { - int i = 0; - - level &= 0x7f; - if (level) - i = (level / 20) - 1; - mode_control &= ~0x03; - mode_control |= i & 0x03; - set_mode(mode_control); - if (i) - i = (i + 1) * 20; - level = i; - } - return put_user(level, p); - } - if (cmd == SOUND_MIXER_PRIVATE3) { /* Set mute bit */ - if (get_user(level, p)) - return -EFAULT; - if (level == -1) /* Return current settings */ - level = !(pas_read(0x0B8A) & 0x20); - else { - if (level) - pas_write(pas_read(0x0B8A) & (~0x20), 0x0B8A); - else - pas_write(pas_read(0x0B8A) | 0x20, 0x0B8A); - - level = !(pas_read(0x0B8A) & 0x20); - } - return put_user(level, p); - } - if (((cmd >> 8) & 0xff) == 'M') { - if (get_user(v, p)) - return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - v = pas_mixer_set(cmd & 0xff, v); - } else { - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - v = rec_devices; - break; - - case SOUND_MIXER_STEREODEVS: - v = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE); - break; - - case SOUND_MIXER_DEVMASK: - v = SUPPORTED_MIXER_DEVICES; - break; - - case SOUND_MIXER_RECMASK: - v = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES; - break; - - case SOUND_MIXER_CAPS: - v = 0; /* No special capabilities */ - break; - - default: - v = levels[cmd & 0xff]; - break; - } - } - return put_user(v, p); - } - return -EINVAL; -} - -static struct mixer_operations pas_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "PAS16", - .name = "Pro Audio Spectrum 16", - .ioctl = pas_mixer_ioctl -}; - -int __init -pas_init_mixer(void) -{ - int d; - - levels = load_mixer_volumes("PAS16_1", default_levels, 1); - - pas_mixer_reset(); - - if ((d = sound_alloc_mixerdev()) != -1) - { - audio_devs[pas_audiodev]->mixer_dev = d; - mixer_devs[d] = &pas_mixer_operations; - } - return 1; -} diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c deleted file mode 100644 index 474803b52f7d..000000000000 --- a/sound/oss/pas2_pcm.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * pas2_pcm.c Audio routines for PAS16 - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Alan Cox : Swatted a double allocation of device bug. Made a few - * more things module options. - * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init() - */ - -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/timex.h> -#include "sound_config.h" - -#include "pas2.h" - -#define PAS_PCM_INTRBITS (0x08) -/* - * Sample buffer timer interrupt enable - */ - -#define PCM_NON 0 -#define PCM_DAC 1 -#define PCM_ADC 2 - -static unsigned long pcm_speed; /* sampling rate */ -static unsigned char pcm_channels = 1; /* channels (1 or 2) */ -static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */ -static unsigned char pcm_filter; /* filter FLAG */ -static unsigned char pcm_mode = PCM_NON; -static unsigned long pcm_count; -static unsigned short pcm_bitsok = 8; /* mask of OK bits */ -static int pcm_busy; -int pas_audiodev = -1; -static int open_mode; - -extern spinlock_t pas_lock; - -static int pcm_set_speed(int arg) -{ - int foo, tmp; - unsigned long flags; - - if (arg == 0) - return pcm_speed; - - if (arg > 44100) - arg = 44100; - if (arg < 5000) - arg = 5000; - - if (pcm_channels & 2) - { - foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg; - arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo; - } - else - { - foo = (PIT_TICK_RATE + (arg / 2)) / arg; - arg = (PIT_TICK_RATE + (foo / 2)) / foo; - } - - pcm_speed = arg; - - tmp = pas_read(0x0B8A); - - /* - * Set anti-aliasing filters according to sample rate. You really *NEED* - * to enable this feature for all normal recording unless you want to - * experiment with aliasing effects. - * These filters apply to the selected "recording" source. - * I (pfw) don't know the encoding of these 5 bits. The values shown - * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. - * - * I cleared bit 5 of these values, since that bit controls the master - * mute flag. (Olav Wölfelschneider) - * - */ -#if !defined NO_AUTO_FILTER_SET - tmp &= 0xe0; - if (pcm_speed >= 2 * 17897) - tmp |= 0x01; - else if (pcm_speed >= 2 * 15909) - tmp |= 0x02; - else if (pcm_speed >= 2 * 11931) - tmp |= 0x09; - else if (pcm_speed >= 2 * 8948) - tmp |= 0x11; - else if (pcm_speed >= 2 * 5965) - tmp |= 0x19; - else if (pcm_speed >= 2 * 2982) - tmp |= 0x04; - pcm_filter = tmp; -#endif - - spin_lock_irqsave(&pas_lock, flags); - - pas_write(tmp & ~(0x40 | 0x80), 0x0B8A); - pas_write(0x00 | 0x30 | 0x04, 0x138B); - pas_write(foo & 0xff, 0x1388); - pas_write((foo >> 8) & 0xff, 0x1388); - pas_write(tmp, 0x0B8A); - - spin_unlock_irqrestore(&pas_lock, flags); - - return pcm_speed; -} - -static int pcm_set_channels(int arg) -{ - - if ((arg != 1) && (arg != 2)) - return pcm_channels; - - if (arg != pcm_channels) - { - pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A); - - pcm_channels = arg; - pcm_set_speed(pcm_speed); /* The speed must be reinitialized */ - } - return pcm_channels; -} - -static int pcm_set_bits(int arg) -{ - if (arg == 0) - return pcm_bits; - - if ((arg & pcm_bitsok) != arg) - return pcm_bits; - - if (arg != pcm_bits) - { - pas_write(pas_read(0x8389) ^ 0x04, 0x8389); - - pcm_bits = arg; - } - return pcm_bits; -} - -static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int val, ret; - int __user *p = arg; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_speed(val); - break; - - case SOUND_PCM_READ_RATE: - ret = pcm_speed; - break; - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_channels(val + 1) - 1; - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_channels(val); - break; - - case SOUND_PCM_READ_CHANNELS: - ret = pcm_channels; - break; - - case SNDCTL_DSP_SETFMT: - if (get_user(val, p)) - return -EFAULT; - ret = pcm_set_bits(val); - break; - - case SOUND_PCM_READ_BITS: - ret = pcm_bits; - break; - - default: - return -EINVAL; - } - return put_user(ret, p); -} - -static void pas_audio_reset(int dev) -{ - pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ -} - -static int pas_audio_open(int dev, int mode) -{ - int err; - unsigned long flags; - - spin_lock_irqsave(&pas_lock, flags); - if (pcm_busy) - { - spin_unlock_irqrestore(&pas_lock, flags); - return -EBUSY; - } - pcm_busy = 1; - spin_unlock_irqrestore(&pas_lock, flags); - - if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) - return err; - - - pcm_count = 0; - open_mode = mode; - - return 0; -} - -static void pas_audio_close(int dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pas_lock, flags); - - pas_audio_reset(dev); - pas_remove_intr(PAS_PCM_INTRBITS); - pcm_mode = PCM_NON; - - pcm_busy = 0; - spin_unlock_irqrestore(&pas_lock, flags); -} - -static void pas_audio_output_block(int dev, unsigned long buf, int count, - int intrflag) -{ - unsigned long flags, cnt; - - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; - - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; - - spin_lock_irqsave(&pas_lock, flags); - - pas_write(pas_read(0xF8A) & ~0x40, - 0xF8A); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - - if (count != pcm_count) - { - pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); - pas_write(0x40 | 0x30 | 0x04, 0x138B); - pas_write(count & 0xff, 0x1389); - pas_write((count >> 8) & 0xff, 0x1389); - pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); - - pcm_count = count; - } - pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); -#ifdef NO_TRIGGER - pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); -#endif - - pcm_mode = PCM_DAC; - - spin_unlock_irqrestore(&pas_lock, flags); -} - -static void pas_audio_start_input(int dev, unsigned long buf, int count, - int intrflag) -{ - unsigned long flags; - int cnt; - - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; - - if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; - - spin_lock_irqsave(&pas_lock, flags); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - - if (count != pcm_count) - { - pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); - pas_write(0x40 | 0x30 | 0x04, 0x138B); - pas_write(count & 0xff, 0x1389); - pas_write((count >> 8) & 0xff, 0x1389); - pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); - - pcm_count = count; - } - pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); -#ifdef NO_TRIGGER - pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); -#endif - - pcm_mode = PCM_ADC; - - spin_unlock_irqrestore(&pas_lock, flags); -} - -#ifndef NO_TRIGGER -static void pas_audio_trigger(int dev, int state) -{ - unsigned long flags; - - spin_lock_irqsave(&pas_lock, flags); - state &= open_mode; - - if (state & PCM_ENABLE_OUTPUT) - pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); - else if (state & PCM_ENABLE_INPUT) - pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); - else - pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); - - spin_unlock_irqrestore(&pas_lock, flags); -} -#endif - -static int pas_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - pas_audio_reset(dev); - return 0; -} - -static int pas_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - pas_audio_reset(dev); - return 0; -} - -static struct audio_driver pas_audio_driver = -{ - .owner = THIS_MODULE, - .open = pas_audio_open, - .close = pas_audio_close, - .output_block = pas_audio_output_block, - .start_input = pas_audio_start_input, - .ioctl = pas_audio_ioctl, - .prepare_for_input = pas_audio_prepare_for_input, - .prepare_for_output = pas_audio_prepare_for_output, - .halt_io = pas_audio_reset, - .trigger = pas_audio_trigger -}; - -void __init pas_pcm_init(struct address_info *hw_config) -{ - pcm_bitsok = 8; - if (pas_read(0xEF8B) & 0x08) - pcm_bitsok |= 16; - - pcm_set_speed(DSP_DEFAULT_SPEED); - - if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - "Pro Audio Spectrum", - &pas_audio_driver, - sizeof(struct audio_driver), - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, - NULL, - hw_config->dma, - hw_config->dma)) < 0) - printk(KERN_WARNING "PAS16: Too many PCM devices available\n"); -} - -void pas_pcm_interrupt(unsigned char status, int cause) -{ - if (cause == 1) - { - /* - * Halt the PCM first. Otherwise we don't have time to start a new - * block before the PCM chip proceeds to the next sample - */ - - if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) - pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); - - switch (pcm_mode) - { - case PCM_DAC: - DMAbuf_outputintr(pas_audiodev, 1); - break; - - case PCM_ADC: - DMAbuf_inputintr(pas_audiodev); - break; - - default: - printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n"); - } - } -} diff --git a/sound/oss/pss.c b/sound/oss/pss.c deleted file mode 100644 index 33c3a442e162..000000000000 --- a/sound/oss/pss.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * sound/oss/pss.c - * - * The low level driver for the Personal Sound System (ECHO ESC614). - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, clean up. - * - * 98-02-21: Vladimir Michl <vladimir.michl@upol.cz> - * Added mixer device for Beethoven ADSP-16 (master volume, - * bass, treble, synth), only for speakers. - * Fixed bug in pss_write (exchange parameters) - * Fixed config port of SB - * Requested two regions for PSS (PSS mixer, PSS config) - * Modified pss_download_boot - * To probe_pss_mss added test for initialize AD1848 - * 98-05-28: Vladimir Michl <vladimir.michl@upol.cz> - * Fixed computation of mixer volumes - * 04-05-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> - * Added code that allows the user to enable his cdrom and/or - * joystick through the module parameters pss_cdrom_port and - * pss_enable_joystick. pss_cdrom_port takes a port address as its - * argument. pss_enable_joystick takes either a 0 or a non-0 as its - * argument. - * 04-06-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> - * Separated some code into new functions for easier reuse. - * Cleaned up and streamlined new code. Added code to allow a user - * to only use this driver for enabling non-sound components - * through the new module parameter pss_no_sound (flag). Added - * code that would allow a user to decide whether the driver should - * reset the configured hardware settings for the PSS board through - * the module parameter pss_keep_settings (flag). This flag will - * allow a user to free up resources in use by this card if needbe, - * furthermore it allows him to use this driver to just enable the - * emulations and then be unloaded as it is no longer needed. Both - * new settings are only available to this driver if compiled as a - * module. The default settings of all new parameters are set to - * load the driver as it did in previous versions. - * 04-07-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> - * Added module parameter pss_firmware to allow the user to tell - * the driver where the firmware file is located. The default - * setting is the previous hardcoded setting "/etc/sound/pss_synth". - * 00-03-03: Christoph Hellwig <chhellwig@infradead.org> - * Adapted to module_init/module_exit - * 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> - * Added __init to probe_pss(), attach_pss() and probe_pss_mpu() - * 02-Jan-2001: Chris Rankin - * Specify that this module owns the coprocessor - */ - - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/spinlock.h> - -#include "sound_config.h" -#include "sound_firmware.h" - -#include "ad1848.h" -#include "mpu401.h" - -/* - * PSS registers. - */ -#define REG(x) (devc->base+x) -#define PSS_DATA 0 -#define PSS_STATUS 2 -#define PSS_CONTROL 2 -#define PSS_ID 4 -#define PSS_IRQACK 4 -#define PSS_PIO 0x1a - -/* - * Config registers - */ -#define CONF_PSS 0x10 -#define CONF_WSS 0x12 -#define CONF_SB 0x14 -#define CONF_CDROM 0x16 -#define CONF_MIDI 0x18 - -/* - * Status bits. - */ -#define PSS_FLAG3 0x0800 -#define PSS_FLAG2 0x0400 -#define PSS_FLAG1 0x1000 -#define PSS_FLAG0 0x0800 -#define PSS_WRITE_EMPTY 0x8000 -#define PSS_READ_FULL 0x4000 - -/* - * WSS registers - */ -#define WSS_INDEX 4 -#define WSS_DATA 5 - -/* - * WSS status bits - */ -#define WSS_INITIALIZING 0x80 -#define WSS_AUTOCALIBRATION 0x20 - -#define NO_WSS_MIXER -1 - -#include "coproc.h" - -#include "pss_boot.h" - -/* If compiled into kernel, it enable or disable pss mixer */ -#ifdef CONFIG_PSS_MIXER -static bool pss_mixer = 1; -#else -static bool pss_mixer; -#endif - - -struct pss_mixerdata { - unsigned int volume_l; - unsigned int volume_r; - unsigned int bass; - unsigned int treble; - unsigned int synth; -}; - -struct pss_confdata { - int base; - int irq; - int dma; - int *osp; - struct pss_mixerdata mixer; - int ad_mixer_dev; -}; - -static struct pss_confdata pss_data; -static struct pss_confdata *devc = &pss_data; -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 bool pss_enable_joystick; /* Parameter for enabling the joystick */ -static coproc_operations pss_coproc_operations; - -static void pss_write(struct pss_confdata *devc, int data) -{ - unsigned long i, limit; - - limit = jiffies + HZ/10; /* The timeout is 0.1 seconds */ - /* - * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 5000000 && time_before(jiffies, limit); i++) - { - if (inw(REG(PSS_STATUS)) & PSS_WRITE_EMPTY) - { - outw(data, REG(PSS_DATA)); - return; - } - } - printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data); -} - -static int __init probe_pss(struct address_info *hw_config) -{ - unsigned short id; - int irq, dma; - - devc->base = hw_config->io_base; - irq = devc->irq = hw_config->irq; - dma = devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - - if (devc->base != 0x220 && devc->base != 0x240) - if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ - return 0; - - 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; -} - -static int set_irq(struct pss_confdata *devc, int dev, int irq) -{ - static unsigned short irq_bits[16] = - { - 0x0000, 0x0000, 0x0000, 0x0008, - 0x0000, 0x0010, 0x0000, 0x0018, - 0x0000, 0x0020, 0x0028, 0x0030, - 0x0038, 0x0000, 0x0000, 0x0000 - }; - - unsigned short tmp, bits; - - if (irq < 0 || irq > 15) - return 0; - - tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ - - if ((bits = irq_bits[irq]) == 0 && irq != 0) - { - printk(KERN_ERR "PSS: Invalid IRQ %d\n", irq); - return 0; - } - outw(tmp | bits, REG(dev)); - return 1; -} - -static void set_io_base(struct pss_confdata *devc, int dev, int base) -{ - unsigned short tmp = inw(REG(dev)) & 0x003f; - unsigned short bits = (base & 0x0ffc) << 4; - - outw(bits | tmp, REG(dev)); -} - -static int set_dma(struct pss_confdata *devc, int dev, int dma) -{ - static unsigned short dma_bits[8] = - { - 0x0001, 0x0002, 0x0000, 0x0003, - 0x0000, 0x0005, 0x0006, 0x0007 - }; - - unsigned short tmp, bits; - - if (dma < 0 || dma > 7) - return 0; - - tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */ - - if ((bits = dma_bits[dma]) == 0 && dma != 4) - { - printk(KERN_ERR "PSS: Invalid DMA %d\n", dma); - return 0; - } - outw(tmp | bits, REG(dev)); - return 1; -} - -static int pss_reset_dsp(struct pss_confdata *devc) -{ - unsigned long i, limit = jiffies + HZ/10; - - outw(0x2000, REG(PSS_CONTROL)); - for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) - inw(REG(PSS_CONTROL)); - outw(0x0000, REG(PSS_CONTROL)); - return 1; -} - -static int pss_put_dspword(struct pss_confdata *devc, unsigned short word) -{ - int i, val; - - for (i = 0; i < 327680; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & PSS_WRITE_EMPTY) - { - outw(word, REG(PSS_DATA)); - return 1; - } - } - return 0; -} - -static int pss_get_dspword(struct pss_confdata *devc, unsigned short *word) -{ - int i, val; - - for (i = 0; i < 327680; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & PSS_READ_FULL) - { - *word = inw(REG(PSS_DATA)); - return 1; - } - } - return 0; -} - -static int pss_download_boot(struct pss_confdata *devc, unsigned char *block, - int size, int flags) -{ - int i, val, count; - unsigned long limit; - - if (flags & CPF_FIRST) - { -/*_____ Warn DSP software that a boot is coming */ - outw(0x00fe, REG(PSS_DATA)); - - limit = jiffies + HZ/10; - for (i = 0; i < 32768 && time_before(jiffies, limit); i++) - if (inw(REG(PSS_DATA)) == 0x5500) - break; - - outw(*block++, REG(PSS_DATA)); - pss_reset_dsp(devc); - } - count = 1; - while ((flags&CPF_LAST) || count<size ) - { - int j; - - for (j = 0; j < 327670; j++) - { -/*_____ Wait for BG to appear */ - if (inw(REG(PSS_STATUS)) & PSS_FLAG3) - break; - } - - if (j == 327670) - { - /* It's ok we timed out when the file was empty */ - if (count >= size && flags & CPF_LAST) - break; - else - { - printk("\n"); - printk(KERN_ERR "PSS: Download timeout problems, byte %d=%d\n", count, size); - return 0; - } - } -/*_____ Send the next byte */ - if (count >= size) - { - /* If not data in block send 0xffff */ - outw (0xffff, REG (PSS_DATA)); - } - else - { - /*_____ Send the next byte */ - outw (*block++, REG (PSS_DATA)); - } - count++; - } - - if (flags & CPF_LAST) - { -/*_____ Why */ - outw(0, REG(PSS_DATA)); - - limit = jiffies + HZ/10; - for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) - val = inw(REG(PSS_STATUS)); - - limit = jiffies + HZ/10; - for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) - { - val = inw(REG(PSS_STATUS)); - if (val & 0x4000) - break; - } - - /* now read the version */ - for (i = 0; i < 32000; i++) - { - val = inw(REG(PSS_STATUS)); - if (val & PSS_READ_FULL) - break; - } - if (i == 32000) - return 0; - - val = inw(REG(PSS_DATA)); - /* printk( "<PSS: microcode version %d.%d loaded>", val/16, val % 16); */ - } - return 1; -} - -/* Mixer */ -static void set_master_volume(struct pss_confdata *devc, int left, int right) -{ - static unsigned char log_scale[101] = { - 0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, - 0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, - 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, - 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, - 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, - 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, - 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, - 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff - }; - pss_write(devc, 0x0010); - pss_write(devc, log_scale[left] | 0x0000); - pss_write(devc, 0x0010); - pss_write(devc, log_scale[right] | 0x0100); -} - -static void set_synth_volume(struct pss_confdata *devc, int volume) -{ - int vol = ((0x8000*volume)/100L); - pss_write(devc, 0x0080); - pss_write(devc, vol); - pss_write(devc, 0x0081); - pss_write(devc, vol); -} - -static void set_bass(struct pss_confdata *devc, int level) -{ - int vol = (int)(((0xfd - 0xf0) * level)/100L) + 0xf0; - pss_write(devc, 0x0010); - pss_write(devc, vol | 0x0200); -}; - -static void set_treble(struct pss_confdata *devc, int level) -{ - int vol = (((0xfd - 0xf0) * level)/100L) + 0xf0; - pss_write(devc, 0x0010); - pss_write(devc, vol | 0x0300); -}; - -static void pss_mixer_reset(struct pss_confdata *devc) -{ - set_master_volume(devc, 33, 33); - set_bass(devc, 50); - set_treble(devc, 50); - set_synth_volume(devc, 30); - pss_write (devc, 0x0010); - pss_write (devc, 0x0800 | 0xce); /* Stereo */ - - if(pss_mixer) - { - devc->mixer.volume_l = devc->mixer.volume_r = 33; - devc->mixer.bass = 50; - devc->mixer.treble = 50; - devc->mixer.synth = 30; - } -} - -static int set_volume_mono(unsigned __user *p, unsigned int *aleft) -{ - unsigned int left, volume; - if (get_user(volume, p)) - return -EFAULT; - - left = volume & 0xff; - if (left > 100) - left = 100; - *aleft = left; - return 0; -} - -static int set_volume_stereo(unsigned __user *p, - unsigned int *aleft, - unsigned int *aright) -{ - unsigned int left, right, 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) -{ - return ((left << 8) | left); -} - -static int ret_vol_stereo(int left, int right) -{ - return ((right << 8) | left); -} - -static int call_ad_mixer(struct 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); - else - return -EINVAL; -} - -static int pss_mixer_ioctl (int dev, unsigned int cmd, void __user *arg) -{ - struct pss_confdata *devc = mixer_devs[dev]->devc; - int cmdf = cmd & 0xff; - - if ((cmdf != SOUND_MIXER_VOLUME) && (cmdf != SOUND_MIXER_BASS) && - (cmdf != SOUND_MIXER_TREBLE) && (cmdf != SOUND_MIXER_SYNTH) && - (cmdf != SOUND_MIXER_DEVMASK) && (cmdf != SOUND_MIXER_STEREODEVS) && - (cmdf != SOUND_MIXER_RECMASK) && (cmdf != SOUND_MIXER_CAPS) && - (cmdf != SOUND_MIXER_RECSRC)) - { - return call_ad_mixer(devc, cmd, arg); - } - - if (((cmd >> 8) & 0xff) != 'M') - return -EINVAL; - - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - { - switch (cmdf) - { - case SOUND_MIXER_RECSRC: - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return call_ad_mixer(devc, cmd, arg); - else - { - int v; - if (get_user(v, (int __user *)arg)) - return -EFAULT; - if (v != 0) - return -EINVAL; - return 0; - } - case SOUND_MIXER_VOLUME: - 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: - 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: - 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: - if (set_volume_mono(arg, &devc->mixer.synth)) - return -EFAULT; - set_synth_volume(devc, devc->mixer.synth); - return ret_vol_mono(devc->mixer.synth); - - default: - return -EINVAL; - } - } - 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) - 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) - 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); - break; - - case SOUND_MIXER_CAPS: - if (devc->ad_mixer_dev != NO_WSS_MIXER) - return call_ad_mixer(devc, cmd, arg); - 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); - break; - - case SOUND_MIXER_VOLUME: - or_mask = ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r); - break; - - case SOUND_MIXER_BASS: - or_mask = ret_vol_mono(devc->mixer.bass); - break; - - case SOUND_MIXER_TREBLE: - or_mask = ret_vol_mono(devc->mixer.treble); - break; - - case SOUND_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; - } -} - -static struct mixer_operations pss_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "SOUNDPORT", - .name = "PSS-AD1848", - .ioctl = pss_mixer_ioctl -}; - -static void disable_all_emulations(void) -{ - outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ - outw(0x0000, REG(CONF_WSS)); - outw(0x0000, REG(CONF_SB)); - outw(0x0000, REG(CONF_MIDI)); - outw(0x0000, REG(CONF_CDROM)); -} - -static void configure_nonsound_components(void) -{ - /* Configure Joystick port */ - - if(pss_enable_joystick) - { - outw(0x0400, REG(CONF_PSS)); /* 0x0400 enables joystick */ - printk(KERN_INFO "PSS: joystick enabled.\n"); - } - else - { - printk(KERN_INFO "PSS: joystick port not enabled.\n"); - } - - /* Configure CDROM port */ - - if (pss_cdrom_port == -1) { /* If cdrom port enablation wasn't requested */ - printk(KERN_INFO "PSS: CDROM port not enabled.\n"); - } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) { - pss_cdrom_port = -1; - printk(KERN_ERR "PSS: CDROM I/O port conflict.\n"); - } else { - set_io_base(devc, CONF_CDROM, pss_cdrom_port); - printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port); - } -} - -static int __init attach_pss(struct address_info *hw_config) -{ - unsigned short id; - char tmp[100]; - - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - devc->ad_mixer_dev = NO_WSS_MIXER; - - if (!probe_pss(hw_config)) - return 0; - - id = inw(REG(PSS_ID)) & 0x00ff; - - /* - * Disable all emulations. Will be enabled later (if required). - */ - - disable_all_emulations(); - -#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"); - 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"); - 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"); - release_region(hw_config->io_base, 0x10); - release_region(hw_config->io_base+0x10, 0x9); - return 0; - } -#endif - - configure_nonsound_components(); - pss_initialized = 1; - sprintf(tmp, "ECHO-PSS Rev. %d", id); - conf_printf(tmp, hw_config); - return 1; -} - -static int __init probe_pss_mpu(struct address_info *hw_config) -{ - struct resource *ports; - int timeout; - - if (!pss_initialized) - return 0; - - ports = request_region(hw_config->io_base, 2, "mpu401"); - - if (!ports) { - printk(KERN_ERR "PSS: MPU I/O port conflict\n"); - return 0; - } - set_io_base(devc, CONF_MIDI, hw_config->io_base); - if (!set_irq(devc, CONF_MIDI, hw_config->irq)) { - printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n"); - goto fail; - } - if (!pss_synthLen) { - printk(KERN_ERR "PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - goto fail; - } - 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"); - goto fail; - } - - /* - * Finally wait until the DSP algorithm has initialized itself and - * deactivates receive interrupt. - */ - - for (timeout = 900000; timeout > 0; timeout--) - { - if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ - inb(hw_config->io_base); /* Discard it */ - else - break; /* No more input */ - } - - 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) -{ - switch (sub_device) - { - case COPR_MIDI: - if (pss_synthLen == 0) - { - printk(KERN_ERR "PSS: MIDI synth microcode not available.\n"); - return -EIO; - } - if (nonstandard_microcode) - 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 -EIO; - } - nonstandard_microcode = 0; - break; - - default: - break; - } - return 0; -} - -static void pss_coproc_close(void *dev_info, int sub_device) -{ - return; -} - -static void pss_coproc_reset(void *dev_info) -{ - if (pss_synthLen) - 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"); - } - nonstandard_microcode = 0; -} - -static int download_boot_block(void *dev_info, copr_buffer * buf) -{ - if (buf->len <= 0 || buf->len > sizeof(buf->data)) - return -EINVAL; - - if (!pss_download_boot(devc, buf->data, buf->len, buf->flags)) - { - printk(KERN_ERR "PSS: Unable to load microcode block to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - return 0; -} - -static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local) -{ - copr_buffer *buf; - copr_msg *mbuf; - copr_debug_buf dbuf; - unsigned short tmp; - unsigned long flags; - unsigned short *data; - int i, err; - /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - - switch (cmd) - { - case SNDCTL_COPR_RESET: - pss_coproc_reset(dev_info); - return 0; - - case SNDCTL_COPR_LOAD: - buf = vmalloc(sizeof(copr_buffer)); - if (buf == NULL) - return -ENOSPC; - if (copy_from_user(buf, arg, sizeof(copr_buffer))) { - vfree(buf); - return -EFAULT; - } - err = download_boot_block(dev_info, buf); - vfree(buf); - return err; - - case SNDCTL_COPR_SENDMSG: - mbuf = vmalloc(sizeof(copr_msg)); - if (mbuf == NULL) - return -ENOSPC; - if (copy_from_user(mbuf, arg, sizeof(copr_msg))) { - vfree(mbuf); - return -EFAULT; - } - data = (unsigned short *)(mbuf->data); - spin_lock_irqsave(&lock, flags); - for (i = 0; i < mbuf->len; i++) { - if (!pss_put_dspword(devc, *data++)) { - spin_unlock_irqrestore(&lock,flags); - mbuf->len = i; /* feed back number of WORDs sent */ - err = copy_to_user(arg, mbuf, sizeof(copr_msg)); - vfree(mbuf); - return err ? -EFAULT : -EIO; - } - } - spin_unlock_irqrestore(&lock,flags); - vfree(mbuf); - return 0; - - case SNDCTL_COPR_RCVMSG: - err = 0; - mbuf = vmalloc(sizeof(copr_msg)); - if (mbuf == NULL) - return -ENOSPC; - data = (unsigned short *)mbuf->data; - spin_lock_irqsave(&lock, flags); - for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) { - mbuf->len = i; /* feed back number of WORDs read */ - if (!pss_get_dspword(devc, data++)) { - if (i == 0) - err = -EIO; - break; - } - } - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(arg, mbuf, sizeof(copr_msg))) - err = -EFAULT; - vfree(mbuf); - return err; - - case SNDCTL_COPR_RDATA: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d0)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_get_dspword(devc, &tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - dbuf.parm1 = tmp; - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(arg, &dbuf, sizeof(dbuf))) - return -EFAULT; - return 0; - - case SNDCTL_COPR_WDATA: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d1)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - tmp = (unsigned int)dbuf.parm2 & 0xffff; - if (!pss_put_dspword(devc, tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - spin_unlock_irqrestore(&lock,flags); - return 0; - - case SNDCTL_COPR_WCODE: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d3)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - tmp = (unsigned int)dbuf.parm2 & 0x00ff; - if (!pss_put_dspword(devc, tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff; - if (!pss_put_dspword(devc, tmp)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - spin_unlock_irqrestore(&lock,flags); - return 0; - - case SNDCTL_COPR_RCODE: - if (copy_from_user(&dbuf, arg, sizeof(dbuf))) - return -EFAULT; - spin_lock_irqsave(&lock, flags); - if (!pss_put_dspword(devc, 0x00d2)) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) { - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */ - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - dbuf.parm1 = tmp << 8; - if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */ - spin_unlock_irqrestore(&lock,flags); - return -EIO; - } - dbuf.parm1 |= tmp & 0x00ff; - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(arg, &dbuf, sizeof(dbuf))) - return -EFAULT; - return 0; - - default: - return -EINVAL; - } - return -EINVAL; -} - -static coproc_operations pss_coproc_operations = -{ - "ADSP-2115", - THIS_MODULE, - pss_coproc_open, - pss_coproc_close, - pss_coproc_ioctl, - pss_coproc_reset, - &pss_data -}; - -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 (!request_region(hw_config->io_base, 4, "WSS config")) { - printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); - return 0; - } - 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; - } - set_io_base(devc, CONF_WSS, hw_config->io_base); - if (!set_irq(devc, CONF_WSS, hw_config->irq)) { - printk("PSS: WSS IRQ allocation error.\n"); - goto fail; - } - if (!set_dma(devc, CONF_WSS, hw_config->dma)) { - printk(KERN_ERR "PSS: WSS DMA allocation error\n"); - goto fail; - } - /* - * For some reason the card returns 0xff in the WSS status register - * immediately after boot. Probably MIDI+SB emulation algorithm - * downloaded to the ADSP2115 spends some time initializing the card. - * Let's try to wait until it finishes this task. - */ - for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) & - WSS_INITIALIZING); timeout++) - ; - - outb((0x0b), hw_config->io_base + WSS_INDEX); /* Required by some cards */ - - for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && - (timeout < 100000); timeout++) - ; - - if (!probe_ms_sound(hw_config, ports)) - goto fail; - - devc->ad_mixer_dev = NO_WSS_MIXER; - if (pss_mixer) - { - if ((my_mix = sound_install_mixer (MIXER_DRIVER_VERSION, - "PSS-SPEAKERS and AD1848 (through MSS audio codec)", - &pss_mixer_operations, - sizeof (struct mixer_operations), - devc)) < 0) - { - printk(KERN_ERR "Could not install PSS mixer\n"); - goto fail; - } - } - pss_mixer_reset(devc); - attach_ms_sound(hw_config, ports, THIS_MODULE); /* Slot 0 */ - - if (hw_config->slots[0] != -1) - { - /* The MSS driver installed itself */ - audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; - if (pss_mixer && (num_mixers == (my_mix + 2))) - { - /* The MSS mixer installed */ - 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) -{ - release_region(hw_config->io_base, 0x10); - release_region(hw_config->io_base+0x10, 0x9); -} - -static inline void __exit unload_pss_mpu(struct address_info *hw_config) -{ - unload_mpu401(hw_config); -} - -static inline void __exit unload_pss_mss(struct address_info *hw_config) -{ - unload_ms_sound(hw_config); -} - - -static struct address_info cfg; -static struct address_info cfg2; -static struct address_info cfg_mpu; - -static int pss_io __initdata = -1; -static int mss_io __initdata = -1; -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 bool pss_no_sound = 0; /* Just configure non-sound components */ -static bool pss_keep_settings = 1; /* Keep hardware settings at module exit */ -static char *pss_firmware = "/etc/sound/pss_synth"; - -module_param_hw(pss_io, int, ioport, 0); -MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)"); -module_param_hw(mss_io, int, ioport, 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_param_hw(mss_irq, int, irq, 0); -MODULE_PARM_DESC(mss_irq, "Set WSS (audio) IRQ (3, 5, 7, 9, 10, 11, 12)"); -module_param_hw(mss_dma, int, dma, 0); -MODULE_PARM_DESC(mss_dma, "Set WSS (audio) DMA (0, 1, 3)"); -module_param_hw(mpu_io, int, ioport, 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_param_hw(mpu_irq, int, irq, 0); -MODULE_PARM_DESC(mpu_irq, "Set MIDI IRQ (3, 5, 7, 9, 10, 11, 12)"); -module_param_hw(pss_cdrom_port, int, ioport, 0); -MODULE_PARM_DESC(pss_cdrom_port, "Set the PSS CDROM port i/o base (0x340 or other)"); -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_param(pss_no_sound, bool, 0); -MODULE_PARM_DESC(pss_no_sound, "Configure sound compoents (0 - no, 1 - yes)"); -module_param(pss_keep_settings, bool, 0); -MODULE_PARM_DESC(pss_keep_settings, "Keep hardware setting at driver unloading (0 - no, 1 - yes)"); -module_param(pss_firmware, charp, 0); -MODULE_PARM_DESC(pss_firmware, "Location of the firmware file (default - /etc/sound/pss_synth)"); -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)."); -MODULE_LICENSE("GPL"); - - -static int fw_load = 0; -static int pssmpu = 0, pssmss = 0; - -/* - * Load a PSS sound card module - */ - -static int __init init_pss(void) -{ - - if(pss_no_sound) /* If configuring only nonsound components */ - { - cfg.io_base = pss_io; - if(!probe_pss(&cfg)) - return -ENODEV; - printk(KERN_INFO "ECHO-PSS Rev. %d\n", inw(REG(PSS_ID)) & 0x00ff); - 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; - } - - cfg.io_base = pss_io; - - cfg2.io_base = mss_io; - cfg2.irq = mss_irq; - cfg2.dma = mss_dma; - - cfg_mpu.io_base = mpu_io; - cfg_mpu.irq = mpu_irq; - - if (cfg.io_base == -1 || cfg2.io_base == -1 || cfg2.irq == -1 || cfg.dma == -1) { - printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n"); - return -EINVAL; - } - - if (!pss_synth) { - fw_load = 1; - pss_synthLen = mod_firmware_load(pss_firmware, (void *) &pss_synth); - } - if (!attach_pss(&cfg)) - return -ENODEV; - /* - * Attach stuff - */ - if (probe_pss_mpu(&cfg_mpu)) - pssmpu = 1; - - if (probe_pss_mss(&cfg2)) - pssmss = 1; - - return 0; -} - -static void __exit cleanup_pss(void) -{ - if(!pss_no_sound) - { - if (fw_load) - vfree(pss_synth); - if(pssmss) - unload_pss_mss(&cfg2); - if(pssmpu) - unload_pss_mpu(&cfg_mpu); - unload_pss(&cfg); - } else if (pss_cdrom_port != -1) - release_region(pss_cdrom_port, 2); - - if(!pss_keep_settings) /* Keep hardware settings if asked */ - { - disable_all_emulations(); - printk(KERN_INFO "Resetting PSS sound card configurations.\n"); - } -} - -module_init(init_pss); -module_exit(cleanup_pss); - -#ifndef MODULE -static int __init setup_pss(char *str) -{ - /* io, mss_io, mss_irq, mss_dma, mpu_io, mpu_irq */ - int ints[7]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - pss_io = ints[1]; - mss_io = ints[2]; - mss_irq = ints[3]; - mss_dma = ints[4]; - mpu_io = ints[5]; - mpu_irq = ints[6]; - - return 1; -} - -__setup("pss=", setup_pss); -#endif diff --git a/sound/oss/sb.h b/sound/oss/sb.h deleted file mode 100644 index bb1d18709b36..000000000000 --- a/sound/oss/sb.h +++ /dev/null @@ -1,186 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define DSP_RESET (devc->base + 0x6) -#define DSP_READ (devc->base + 0xA) -#define DSP_WRITE (devc->base + 0xC) -#define DSP_COMMAND (devc->base + 0xC) -#define DSP_STATUS (devc->base + 0xC) -#define DSP_DATA_AVAIL (devc->base + 0xE) -#define DSP_DATA_AVL16 (devc->base + 0xF) -#define MIXER_ADDR (devc->base + 0x4) -#define MIXER_DATA (devc->base + 0x5) -#define OPL3_LEFT (devc->base + 0x0) -#define OPL3_RIGHT (devc->base + 0x2) -#define OPL3_BOTH (devc->base + 0x8) -/* DSP Commands */ - -#define DSP_CMD_SPKON 0xD1 -#define DSP_CMD_SPKOFF 0xD3 -#define DSP_CMD_DMAON 0xD0 -#define DSP_CMD_DMAOFF 0xD4 - -#define IMODE_NONE 0 -#define IMODE_OUTPUT PCM_ENABLE_OUTPUT -#define IMODE_INPUT PCM_ENABLE_INPUT -#define IMODE_INIT 3 -#define IMODE_MIDI 4 - -#define NORMAL_MIDI 0 -#define UART_MIDI 1 - - -/* - * Device models - */ -#define MDL_NONE 0 -#define MDL_SB1 1 /* SB1.0 or 1.5 */ -#define MDL_SB2 2 /* SB2.0 */ -#define MDL_SB201 3 /* SB2.01 */ -#define MDL_SBPRO 4 /* SB Pro */ -#define MDL_SB16 5 /* SB16/32/AWE */ -#define MDL_SBPNP 6 /* SB16/32/AWE PnP */ -#define MDL_JAZZ 10 /* Media Vision Jazz16 */ -#define MDL_SMW 11 /* Logitech SoundMan Wave (Jazz16) */ -#define MDL_ESS 12 /* ESS ES688 and ES1688 */ -#define MDL_AZTECH 13 /* Aztech Sound Galaxy family */ -#define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ -#define MDL_AEDSP 15 /* Audio Excel DSP 16 */ -#define MDL_ESSPCI 16 /* ESS PCI card */ -#define MDL_YMPCI 17 /* Yamaha PCI sb in emulation */ - -#define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ - /* register assignment */ -#define SUBMDL_ALS100 43 /* ALS-100 allows sampling rates of up */ - /* to 48kHz */ - -/* - * Config flags - */ -#define SB_NO_MIDI 0x00000001 -#define SB_NO_MIXER 0x00000002 -#define SB_NO_AUDIO 0x00000004 -#define SB_NO_RECORDING 0x00000008 /* No audio recording */ -#define SB_MIDI_ONLY (SB_NO_AUDIO|SB_NO_MIXER) -#define SB_PCI_IRQ 0x00000010 /* PCI shared IRQ */ - -struct mixer_def { - unsigned int regno: 8; - unsigned int bitoffs:4; - unsigned int nbits:4; -}; - -typedef struct mixer_def mixer_tab[32][2]; -typedef struct mixer_def mixer_ent; - -struct sb_module_options -{ - int esstype; /* ESS chip type */ - int acer; /* Do acer notebook init? */ - int sm_games; /* Logitech soundman games? */ -}; - -typedef struct sb_devc { - int dev; - - /* Hardware parameters */ - int *osp; - int minor, major; - int type; - int model, submodel; - int caps; -# define SBCAP_STEREO 0x00000001 -# define SBCAP_16BITS 0x00000002 - - /* Hardware resources */ - int base; - int irq; - int dma8, dma16; - - int pcibase; /* For ESS Maestro etc */ - - /* State variables */ - int opened; - /* new audio fields for full duplex support */ - int fullduplex; - int duplex; - int speed, bits, channels; - volatile int irq_ok; - volatile int intr_active, irq_mode; - /* duplicate audio fields for full duplex support */ - volatile int intr_active_16, irq_mode_16; - - /* Mixer fields */ - int *levels; - mixer_tab *iomap; - size_t iomap_sz; /* number or records in the iomap table */ - int mixer_caps, recmask, outmask, supported_devices; - int supported_rec_devices, supported_out_devices; - int my_mixerdev; - int sbmixnum; - - /* Audio fields */ - unsigned long trg_buf; - int trigger_bits; - int trg_bytes; - int trg_intrflag; - int trg_restart; - /* duplicate audio fields for full duplex support */ - unsigned long trg_buf_16; - int trigger_bits_16; - int trg_bytes_16; - int trg_intrflag_16; - int trg_restart_16; - - unsigned char tconst; - - /* MIDI fields */ - int my_mididev; - int input_opened; - int midi_broken; - void (*midi_input_intr) (int dev, unsigned char data); - void *midi_irq_cookie; /* IRQ cookie for the midi */ - - spinlock_t lock; - - struct sb_module_options sbmo; /* Module options */ - - } sb_devc; - -/* - * PCI card types - */ - -#define SB_PCI_ESSMAESTRO 1 /* ESS Maestro Legacy */ -#define SB_PCI_YAMAHA 2 /* Yamaha Legacy */ - -/* - * Functions - */ - -int sb_dsp_command (sb_devc *devc, unsigned char val); -int sb_dsp_get_byte(sb_devc * devc); -int sb_dsp_reset (sb_devc *devc); -void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); -unsigned int sb_getmixer (sb_devc *devc, unsigned int port); -int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo); -int sb_dsp_init (struct address_info *hw_config, struct module *owner); -void sb_dsp_unload(struct address_info *hw_config, int sbmpu); -int sb_mixer_init(sb_devc *devc, struct module *owner); -void sb_mixer_unload(sb_devc *devc); -void sb_mixer_set_stereo (sb_devc *devc, int mode); -void smw_mixer_init(sb_devc *devc); -void sb_dsp_midi_init (sb_devc *devc, struct module *owner); -void sb_audio_init (sb_devc *devc, char *name, struct module *owner); -void sb_midi_interrupt (sb_devc *devc); -void sb_chgmixer (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val); -int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right); - -int sb_audio_open(int dev, int mode); -void sb_audio_close(int dev); - -/* From sb_common.c */ -void sb_dsp_disable_midi(int port); -int probe_sbmpu (struct address_info *hw_config, struct module *owner); -void unload_sbmpu (struct address_info *hw_config); - -void unload_sb16(struct address_info *hw_info); -void unload_sb16midi(struct address_info *hw_info); diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c deleted file mode 100644 index dc91072f4d82..000000000000 --- a/sound/oss/sb_audio.c +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * sound/oss/sb_audio.c - * - * Audio routines for Sound Blaster compatible cards. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes - * Alan Cox : Formatting and clean ups - * - * Status - * Mostly working. Weird uart bug causing irq storms - * - * Daniel J. Rodriksson: Changes to make sb16 work full duplex. - * Maybe other 16 bit cards in this code could behave - * the same. - * Chris Rankin: Use spinlocks instead of CLI/STI - */ - -#include <linux/spinlock.h> - -#include "sound_config.h" - -#include "sb_mixer.h" -#include "sb.h" - -#include "sb_ess.h" - -int sb_audio_open(int dev, int mode) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - { - printk(KERN_ERR "Sound Blaster: incomplete initialization.\n"); - return -ENXIO; - } - if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) - { - if (mode == OPEN_READ) - return -EPERM; - } - spin_lock_irqsave(&devc->lock, flags); - if (devc->opened) - { - spin_unlock_irqrestore(&devc->lock, flags); - return -EBUSY; - } - if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) - { - if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) - { - spin_unlock_irqrestore(&devc->lock, flags); - return -EBUSY; - } - } - devc->opened = mode; - spin_unlock_irqrestore(&devc->lock, flags); - - devc->irq_mode = IMODE_NONE; - devc->irq_mode_16 = IMODE_NONE; - devc->fullduplex = devc->duplex && - ((mode & OPEN_READ) && (mode & OPEN_WRITE)); - sb_dsp_reset(devc); - - /* At first glance this check isn't enough, some ESS chips might not - * have a RECLEV. However if they don't common_mixer_set will refuse - * cause devc->iomap has no register mapping for RECLEV - */ - if (devc->model == MDL_ESS) ess_mixer_reload (devc, SOUND_MIXER_RECLEV); - - /* The ALS007 seems to require that the DSP be removed from the output */ - /* in order for recording to be activated properly. This is done by */ - /* setting the appropriate bits of the output control register 4ch to */ - /* zero. This code assumes that the output control registers are not */ - /* used anywhere else and therefore the DSP bits are *always* ON for */ - /* output and OFF for sampling. */ - - if (devc->submodel == SUBMDL_ALS007) - { - if (mode & OPEN_READ) - sb_setmixer(devc,ALS007_OUTPUT_CTRL2, - sb_getmixer(devc,ALS007_OUTPUT_CTRL2) & 0xf9); - else - sb_setmixer(devc,ALS007_OUTPUT_CTRL2, - sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); - } - return 0; -} - -void sb_audio_close(int dev) -{ - sb_devc *devc = audio_devs[dev]->devc; - - /* fix things if mmap turned off fullduplex */ - if(devc->duplex - && !devc->fullduplex - && (devc->opened & OPEN_READ) && (devc->opened & OPEN_WRITE)) - swap(audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_in); - - audio_devs[dev]->dmap_out->dma = devc->dma8; - audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ? - devc->dma16 : devc->dma8; - - if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) - sound_close_dma(devc->dma16); - - /* For ALS007, turn DSP output back on if closing the device for read */ - - if ((devc->submodel == SUBMDL_ALS007) && (devc->opened & OPEN_READ)) - { - sb_setmixer(devc,ALS007_OUTPUT_CTRL2, - sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); - } - devc->opened = 0; -} - -static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, - int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex || devc->bits == AFMT_S16_LE) - { - devc->trg_buf = buf; - devc->trg_bytes = nr_bytes; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_OUTPUT; - } - else - { - devc->trg_buf_16 = buf; - devc->trg_bytes_16 = nr_bytes; - devc->trg_intrflag_16 = intrflag; - devc->irq_mode_16 = IMODE_OUTPUT; - } -} - -static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex || devc->bits != AFMT_S16_LE) - { - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; - } - else - { - devc->trg_buf_16 = buf; - devc->trg_bytes_16 = count; - devc->trg_intrflag_16 = intrflag; - devc->irq_mode_16 = IMODE_INPUT; - } -} - -/* - * SB1.x compatible routines - */ - -static void sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x14)) /* 8 bit DAC using DMA */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - } - else - printk(KERN_WARNING "Sound Blaster: unable to start DAC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - devc->intr_active = 1; -} - -static void sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x24)) /* 8 bit ADC using DMA */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - } - else - printk(KERN_ERR "Sound Blaster: unable to start ADC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - - devc->intr_active = 1; -} - -static void sb1_audio_trigger(int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - bits &= devc->irq_mode; - - if (!bits) - sb_dsp_command(devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } - devc->trigger_bits = bits; -} - -static int sb1_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x40)) - sb_dsp_command(devc, devc->tconst); - sb_dsp_command(devc, DSP_CMD_SPKOFF); - spin_unlock_irqrestore(&devc->lock, flags); - - devc->trigger_bits = 0; - return 0; -} - -static int sb1_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x40)) - sb_dsp_command(devc, devc->tconst); - sb_dsp_command(devc, DSP_CMD_SPKON); - spin_unlock_irqrestore(&devc->lock, flags); - devc->trigger_bits = 0; - return 0; -} - -static int sb1_audio_set_speed(int dev, int speed) -{ - int max_speed = 23000; - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - - if (devc->opened & OPEN_READ) - max_speed = 13000; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > max_speed) - speed = max_speed; - - devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - tmp = 256 - devc->tconst; - speed = (1000000 + tmp / 2) / tmp; - - devc->speed = speed; - } - return devc->speed; -} - -static short sb1_audio_set_channels(int dev, short channels) -{ - sb_devc *devc = audio_devs[dev]->devc; - return devc->channels = 1; -} - -static unsigned int sb1_audio_set_bits(int dev, unsigned int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - return devc->bits = 8; -} - -static void sb1_audio_halt_xfer(int dev) -{ - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; - - spin_lock_irqsave(&devc->lock, flags); - sb_dsp_reset(devc); - spin_unlock_irqrestore(&devc->lock, flags); -} - -/* - * SB 2.0 and SB 2.01 compatible routines - */ - -static void sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes, - int intrflag) -{ - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= 23000) - cmd = 0x1c; /* 8 bit PCM output */ - else - cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ - - if (!sb_dsp_command(devc, cmd)) - printk(KERN_ERR "Sound Blaster: unable to start DAC.\n"); - } - else - printk(KERN_ERR "Sound Blaster: unable to start DAC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - devc->intr_active = 1; -} - -static void sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) - cmd = 0x2c; /* 8 bit PCM input */ - else - cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ - - if (!sb_dsp_command(devc, cmd)) - printk(KERN_ERR "Sound Blaster: unable to start ADC.\n"); - } - else - printk(KERN_ERR "Sound Blaster: unable to start ADC.\n"); - spin_unlock_irqrestore(&devc->lock, flags); - devc->intr_active = 1; -} - -static void sb20_audio_trigger(int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; - - if (!bits) - sb_dsp_command(devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } - devc->trigger_bits = bits; -} - -/* - * SB2.01 specific speed setup - */ - -static int sb201_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - int s; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - if (speed > 44100) - speed = 44100; - if (devc->opened & OPEN_READ && speed > 15000) - speed = 15000; - s = speed * devc->channels; - devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - - devc->speed = speed; - } - return devc->speed; -} - -/* - * SB Pro specific routines - */ - -static int sbpro_audio_prepare_for_input(int dev, int bsize, int bcount) -{ /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char bits = 0; - - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; - - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x40)) - sb_dsp_command(devc, devc->tconst); - sb_dsp_command(devc, DSP_CMD_SPKOFF); - if (devc->channels == 1) - sb_dsp_command(devc, 0xa0 | bits); /* Mono input */ - else - sb_dsp_command(devc, 0xa8 | bits); /* Stereo input */ - spin_unlock_irqrestore(&devc->lock, flags); - - devc->trigger_bits = 0; - return 0; -} - -static int sbpro_audio_prepare_for_output(int dev, int bsize, int bcount) -{ /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char tmp; - unsigned char bits = 0; - - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = devc->bits == 16 ? devc->dma16 : devc->dma8; - if (devc->model == MDL_SBPRO) - sb_mixer_set_stereo(devc, devc->channels == 2); - - spin_lock_irqsave(&devc->lock, flags); - if (sb_dsp_command(devc, 0x40)) - sb_dsp_command(devc, devc->tconst); - sb_dsp_command(devc, DSP_CMD_SPKON); - - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - { - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - if (devc->channels == 1) - sb_dsp_command(devc, 0xa0 | bits); /* Mono output */ - else - sb_dsp_command(devc, 0xa8 | bits); /* Stereo output */ - spin_unlock_irqrestore(&devc->lock, flags); - } - else - { - spin_unlock_irqrestore(&devc->lock, flags); - tmp = sb_getmixer(devc, 0x0e); - if (devc->channels == 1) - tmp &= ~0x02; - else - tmp |= 0x02; - sb_setmixer(devc, 0x0e, tmp); - } - devc->trigger_bits = 0; - return 0; -} - -static int sbpro_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - if (speed > 44100) - speed = 44100; - if (devc->channels > 1 && speed > 22050) - speed = 22050; - sb201_audio_set_speed(dev, speed); - } - return devc->speed; -} - -static short sbpro_audio_set_channels(int dev, short channels) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (channels == 1 || channels == 2) - { - if (channels != devc->channels) - { - devc->channels = channels; - if (devc->model == MDL_SBPRO && devc->channels == 2) - sbpro_audio_set_speed(dev, devc->speed); - } - } - return devc->channels; -} - -static int jazz16_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - int tmp; - int s; - - if (speed < 5000) - speed = 5000; - if (speed > 44100) - speed = 44100; - - s = speed * devc->channels; - - devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff; - - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - - devc->speed = speed; - } - return devc->speed; -} - -/* - * SB16 specific routines - */ - -static int sb16_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - int max_speed = devc->submodel == SUBMDL_ALS100 ? 48000 : 44100; - - if (speed > 0) - { - if (speed < 5000) - speed = 5000; - - if (speed > max_speed) - speed = max_speed; - - devc->speed = speed; - } - return devc->speed; -} - -static unsigned int sb16_audio_set_bits(int dev, unsigned int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (bits != 0) - { - if (bits == AFMT_U8 || bits == AFMT_S16_LE) - devc->bits = bits; - else - devc->bits = AFMT_U8; - } - - return devc->bits; -} - -static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex) - { - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? - devc->dma16 : devc->dma8; - } - else if (devc->bits == AFMT_S16_LE) - { - audio_devs[dev]->dmap_out->dma = devc->dma8; - audio_devs[dev]->dmap_in->dma = devc->dma16; - } - else - { - audio_devs[dev]->dmap_out->dma = devc->dma16; - audio_devs[dev]->dmap_in->dma = devc->dma8; - } - - devc->trigger_bits = 0; - return 0; -} - -static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex) - { - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? - devc->dma16 : devc->dma8; - } - else if (devc->bits == AFMT_S16_LE) - { - audio_devs[dev]->dmap_out->dma = devc->dma8; - audio_devs[dev]->dmap_in->dma = devc->dma16; - } - else - { - audio_devs[dev]->dmap_out->dma = devc->dma16; - audio_devs[dev]->dmap_in->dma = devc->dma8; - } - - devc->trigger_bits = 0; - return 0; -} - -static void sb16_audio_output_block(int dev, unsigned long buf, int count, - int intrflag) -{ - unsigned long flags, cnt; - sb_devc *devc = audio_devs[dev]->devc; - unsigned long bits; - - if (!devc->fullduplex || devc->bits == AFMT_S16_LE) - { - devc->irq_mode = IMODE_OUTPUT; - devc->intr_active = 1; - } - else - { - devc->irq_mode_16 = IMODE_OUTPUT; - devc->intr_active_16 = 1; - } - - /* save value */ - spin_lock_irqsave(&devc->lock, flags); - bits = devc->bits; - if (devc->fullduplex) - devc->bits = (devc->bits == AFMT_S16_LE) ? - AFMT_U8 : AFMT_S16_LE; - spin_unlock_irqrestore(&devc->lock, flags); - - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; - - spin_lock_irqsave(&devc->lock, flags); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - sb_dsp_command(devc, 0x41); - sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); - sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); - - sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); - sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + - (devc->bits == AFMT_S16_LE ? 0x10 : 0))); - sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); - sb_dsp_command(devc, (unsigned char) (cnt >> 8)); - - /* restore real value after all programming */ - devc->bits = bits; - spin_unlock_irqrestore(&devc->lock, flags); -} - - -/* - * This fails on the Cyrix MediaGX. If you don't have the DMA enabled - * before the first sample arrives it locks up. However even if you - * do enable the DMA in time you just get DMA timeouts and missing - * interrupts and stuff, so for now I've not bothered fixing this either. - */ - -static void sb16_audio_start_input(int dev, unsigned long buf, int count, int intrflag) -{ - unsigned long flags, cnt; - sb_devc *devc = audio_devs[dev]->devc; - - if (!devc->fullduplex || devc->bits != AFMT_S16_LE) - { - devc->irq_mode = IMODE_INPUT; - devc->intr_active = 1; - } - else - { - devc->irq_mode_16 = IMODE_INPUT; - devc->intr_active_16 = 1; - } - - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; - - spin_lock_irqsave(&devc->lock, flags); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - sb_dsp_command(devc, 0x42); - sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); - sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); - - sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); - sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + - (devc->bits == AFMT_S16_LE ? 0x10 : 0))); - sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); - sb_dsp_command(devc, (unsigned char) (cnt >> 8)); - - spin_unlock_irqrestore(&devc->lock, flags); -} - -static void sb16_audio_trigger(int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - int bits_16 = bits & devc->irq_mode_16; - bits &= devc->irq_mode; - - if (!bits && !bits_16) - sb_dsp_command(devc, 0xd0); /* Halt DMA */ - else - { - if (bits) - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb16_audio_start_input(dev, - devc->trg_buf, - devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb16_audio_output_block(dev, - devc->trg_buf, - devc->trg_bytes, - devc->trg_intrflag); - break; - } - } - if (bits_16) - { - switch (devc->irq_mode_16) - { - case IMODE_INPUT: - sb16_audio_start_input(dev, - devc->trg_buf_16, - devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - - case IMODE_OUTPUT: - sb16_audio_output_block(dev, - devc->trg_buf_16, - devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - } - } - } - - devc->trigger_bits = bits | bits_16; -} - -static unsigned char lbuf8[2048]; -static signed short *lbuf16 = (signed short *)lbuf8; -#define LBUFCOPYSIZE 1024 -static void -sb16_copy_from_user(int dev, - char *localbuf, int localoffs, - const char __user *userbuf, int useroffs, - int max_in, int max_out, - int *used, int *returned, - int len) -{ - sb_devc *devc = audio_devs[dev]->devc; - int i, c, p, locallen; - unsigned char *buf8; - signed short *buf16; - - /* if not duplex no conversion */ - if (!devc->fullduplex) - { - if (copy_from_user(localbuf + localoffs, - userbuf + useroffs, len)) - return; - *used = len; - *returned = len; - } - else if (devc->bits == AFMT_S16_LE) - { - /* 16 -> 8 */ - /* max_in >> 1, max number of samples in ( 16 bits ) */ - /* max_out, max number of samples out ( 8 bits ) */ - /* len, number of samples that will be taken ( 16 bits )*/ - /* c, count of samples remaining in buffer ( 16 bits )*/ - /* p, count of samples already processed ( 16 bits )*/ - len = ( (max_in >> 1) > max_out) ? max_out : (max_in >> 1); - c = len; - p = 0; - buf8 = (unsigned char *)(localbuf + localoffs); - while (c) - { - locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); - /* << 1 in order to get 16 bit samples */ - if (copy_from_user(lbuf16, - userbuf + useroffs + (p << 1), - locallen << 1)) - return; - for (i = 0; i < locallen; i++) - { - buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80; - } - c -= locallen; p += locallen; - } - /* used = ( samples * 16 bits size ) */ - *used = max_in > ( max_out << 1) ? (max_out << 1) : max_in; - /* returned = ( samples * 8 bits size ) */ - *returned = len; - } - else - { - /* 8 -> 16 */ - /* max_in, max number of samples in ( 8 bits ) */ - /* max_out >> 1, max number of samples out ( 16 bits ) */ - /* len, number of samples that will be taken ( 8 bits )*/ - /* c, count of samples remaining in buffer ( 8 bits )*/ - /* p, count of samples already processed ( 8 bits )*/ - len = max_in > (max_out >> 1) ? (max_out >> 1) : max_in; - c = len; - p = 0; - buf16 = (signed short *)(localbuf + localoffs); - while (c) - { - locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); - if (copy_from_user(lbuf8, - userbuf+useroffs + p, - locallen)) - return; - for (i = 0; i < locallen; i++) - { - buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8; - } - c -= locallen; p += locallen; - } - /* used = ( samples * 8 bits size ) */ - *used = len; - /* returned = ( samples * 16 bits size ) */ - *returned = len << 1; - } -} - -static void -sb16_audio_mmap(int dev) -{ - sb_devc *devc = audio_devs[dev]->devc; - devc->fullduplex = 0; -} - -static struct audio_driver sb1_audio_driver = /* SB1.x */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb1_audio_prepare_for_input, - .prepare_for_output = sb1_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb1_audio_trigger, - .set_speed = sb1_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sb1_audio_set_channels -}; - -static struct audio_driver sb20_audio_driver = /* SB2.0 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb1_audio_prepare_for_input, - .prepare_for_output = sb1_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = sb1_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sb1_audio_set_channels -}; - -static struct audio_driver sb201_audio_driver = /* SB2.01 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb1_audio_prepare_for_input, - .prepare_for_output = sb1_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = sb201_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sb1_audio_set_channels -}; - -static struct audio_driver sbpro_audio_driver = /* SB Pro */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sbpro_audio_prepare_for_input, - .prepare_for_output = sbpro_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = sbpro_audio_set_speed, - .set_bits = sb1_audio_set_bits, - .set_channels = sbpro_audio_set_channels -}; - -static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sbpro_audio_prepare_for_input, - .prepare_for_output = sbpro_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .trigger = sb20_audio_trigger, - .set_speed = jazz16_audio_set_speed, - .set_bits = sb16_audio_set_bits, - .set_channels = sbpro_audio_set_channels -}; - -static struct audio_driver sb16_audio_driver = /* SB16 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = sb_set_output_parms, - .start_input = sb_set_input_parms, - .prepare_for_input = sb16_audio_prepare_for_input, - .prepare_for_output = sb16_audio_prepare_for_output, - .halt_io = sb1_audio_halt_xfer, - .copy_user = sb16_copy_from_user, - .trigger = sb16_audio_trigger, - .set_speed = sb16_audio_set_speed, - .set_bits = sb16_audio_set_bits, - .set_channels = sbpro_audio_set_channels, - .mmap = sb16_audio_mmap -}; - -void sb_audio_init(sb_devc * devc, char *name, struct module *owner) -{ - int audio_flags = 0; - int format_mask = AFMT_U8; - - struct audio_driver *driver = &sb1_audio_driver; - - switch (devc->model) - { - case MDL_SB1: /* SB1.0 or SB 1.5 */ - DDB(printk("Will use standard SB1.x driver\n")); - audio_flags = DMA_HARDSTOP; - break; - - case MDL_SB2: - DDB(printk("Will use SB2.0 driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sb20_audio_driver; - break; - - case MDL_SB201: - DDB(printk("Will use SB2.01 (high speed) driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sb201_audio_driver; - break; - - case MDL_JAZZ: - case MDL_SMW: - DDB(printk("Will use Jazz16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &jazz16_audio_driver; - break; - - case MDL_ESS: - DDB(printk("Will use ESS ES688/1688 driver\n")); - driver = ess_audio_init (devc, &audio_flags, &format_mask); - break; - - case MDL_SB16: - DDB(printk("Will use SB16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - if (devc->dma8 != devc->dma16 && devc->dma16 != -1) - { - audio_flags |= DMA_DUPLEX; - devc->duplex = 1; - } - driver = &sb16_audio_driver; - break; - - default: - DDB(printk("Will use SB Pro driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sbpro_audio_driver; - } - - if (owner) - driver->owner = owner; - - if ((devc->dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - name,driver, sizeof(struct audio_driver), - audio_flags, format_mask, devc, - devc->dma8, - devc->duplex ? devc->dma16 : devc->dma8)) < 0) - { - printk(KERN_ERR "Sound Blaster: unable to install audio.\n"); - return; - } - audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev; - audio_devs[devc->dev]->min_fragment = 5; -} diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c deleted file mode 100644 index 2a92cfe6cfe9..000000000000 --- a/sound/oss/sb_card.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * sound/oss/sb_card.c - * - * Detection routine for the ISA Sound Blaster and compatible sound - * cards. - * - * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this - * software for more info. - * - * This is a complete rewrite of the detection routines. This was - * prompted by the PnP API change during v2.5 and the ugly state the - * code was in. - * - * Copyright (C) by Paul Laufer 2002. Based on code originally by - * Hannu Savolainen which was modified by many others over the - * years. Authors specifically mentioned in the previous version were: - * Daniel Stone, Alessandro Zummo, Jeff Garzik, Arnaldo Carvalho de - * Melo, Daniel Church, and myself. - * - * 02-05-2003 Original Release, Paul Laufer <paul@laufernet.com> - * 02-07-2003 Bug made it into first release. Take two. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/init.h> -#include "sound_config.h" -#include "sb_mixer.h" -#include "sb.h" -#ifdef CONFIG_PNP -#include <linux/pnp.h> -#endif /* CONFIG_PNP */ -#include "sb_card.h" - -MODULE_DESCRIPTION("OSS Soundblaster ISA PnP and legacy sound driver"); -MODULE_LICENSE("GPL"); - -extern void *smw_free; - -static int __initdata mpu_io = 0; -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma16 = -1; -static int __initdata type = 0; /* Can set this to a specific card type */ -static int __initdata esstype = 0; /* ESS chip type */ -static int __initdata acer = 0; /* Do acer notebook init? */ -static int __initdata sm_games = 0; /* Logitech soundman games? */ - -static struct sb_card_config *legacy = NULL; - -#ifdef CONFIG_PNP -static int pnp_registered; -static int __initdata pnp = 1; -/* -static int __initdata uart401 = 0; -*/ -#else -static int __initdata pnp = 0; -#endif - -module_param_hw(io, int, ioport, 000); -MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); -module_param_hw(irq, int, irq, 000); -MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)"); -module_param_hw(dma, int, dma, 000); -MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)"); -module_param_hw(dma16, int, dma, 000); -MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)"); -module_param_hw(mpu_io, int, ioport, 000); -MODULE_PARM_DESC(mpu_io, "MPU base address"); -module_param(type, int, 000); -MODULE_PARM_DESC(type, "You can set this to specific card type (doesn't " \ - "work with pnp)"); -module_param(sm_games, int, 000); -MODULE_PARM_DESC(sm_games, "Enable support for Logitech soundman games " \ - "(doesn't work with pnp)"); -module_param(esstype, int, 000); -MODULE_PARM_DESC(esstype, "ESS chip type (doesn't work with pnp)"); -module_param(acer, int, 000); -MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks "\ - "(doesn't work with pnp)"); - -#ifdef CONFIG_PNP -module_param(pnp, int, 000); -MODULE_PARM_DESC(pnp, "Went set to 0 will disable detection using PnP. "\ - "Default is 1.\n"); -/* Not done yet.... */ -/* -module_param(uart401, int, 000); -MODULE_PARM_DESC(uart401, "When set to 1, will attempt to detect and enable"\ - "the mpu on some clones"); -*/ -#endif /* CONFIG_PNP */ - -/* OSS subsystem card registration shared by PnP and legacy routines */ -static int sb_register_oss(struct sb_card_config *scc, struct sb_module_options *sbmo) -{ - if (!request_region(scc->conf.io_base, 16, "soundblaster")) { - printk(KERN_ERR "sb: ports busy.\n"); - kfree(scc); - return -EBUSY; - } - - if (!sb_dsp_detect(&scc->conf, 0, 0, sbmo)) { - release_region(scc->conf.io_base, 16); - printk(KERN_ERR "sb: Failed DSP Detect.\n"); - kfree(scc); - return -ENODEV; - } - if(!sb_dsp_init(&scc->conf, THIS_MODULE)) { - printk(KERN_ERR "sb: Failed DSP init.\n"); - kfree(scc); - return -ENODEV; - } - if(scc->mpucnf.io_base > 0) { - scc->mpu = 1; - printk(KERN_INFO "sb: Turning on MPU\n"); - if(!probe_sbmpu(&scc->mpucnf, THIS_MODULE)) - scc->mpu = 0; - } - - return 1; -} - -static void sb_unload(struct sb_card_config *scc) -{ - sb_dsp_unload(&scc->conf, 0); - if(scc->mpu) - unload_sbmpu(&scc->mpucnf); - kfree(scc); -} - -/* Register legacy card with OSS subsystem */ -static int __init sb_init_legacy(void) -{ - struct sb_module_options sbmo = {0}; - - if((legacy = kzalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "sb: Error: Could not allocate memory\n"); - return -ENOMEM; - } - - legacy->conf.io_base = io; - legacy->conf.irq = irq; - legacy->conf.dma = dma; - legacy->conf.dma2 = dma16; - legacy->conf.card_subtype = type; - - legacy->mpucnf.io_base = mpu_io; - legacy->mpucnf.irq = -1; - legacy->mpucnf.dma = -1; - legacy->mpucnf.dma2 = -1; - - sbmo.esstype = esstype; - sbmo.sm_games = sm_games; - sbmo.acer = acer; - - return sb_register_oss(legacy, &sbmo); -} - -#ifdef CONFIG_PNP - -/* Populate the OSS subsystem structures with information from PnP */ -static void sb_dev2cfg(struct pnp_dev *dev, struct sb_card_config *scc) -{ - scc->conf.io_base = -1; - scc->conf.irq = -1; - scc->conf.dma = -1; - scc->conf.dma2 = -1; - scc->mpucnf.io_base = -1; - scc->mpucnf.irq = -1; - scc->mpucnf.dma = -1; - scc->mpucnf.dma2 = -1; - - /* All clones layout their PnP tables differently and some use - different logical devices for the MPU */ - if(!strncmp("CTL",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - scc->mpucnf.io_base = pnp_port_start(dev,1); - return; - } - if(!strncmp("tBA",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - return; - } - if(!strncmp("ESS",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - scc->mpucnf.io_base = pnp_port_start(dev,2); - return; - } - if(!strncmp("CMI",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - scc->conf.dma2 = pnp_dma(dev,1); - return; - } - if(!strncmp("RWB",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - return; - } - if(!strncmp("ALS",scc->card_id,3)) { - if(!strncmp("ALS0007",scc->card_id,7)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,0); - } else { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,1); - scc->conf.dma2 = pnp_dma(dev,0); - } - return; - } - if(!strncmp("RTL",scc->card_id,3)) { - scc->conf.io_base = pnp_port_start(dev,0); - scc->conf.irq = pnp_irq(dev,0); - scc->conf.dma = pnp_dma(dev,1); - scc->conf.dma2 = pnp_dma(dev,0); - } -} - -static unsigned int sb_pnp_devices; - -/* Probe callback function for the PnP API */ -static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id) -{ - struct sb_card_config *scc; - struct sb_module_options sbmo = {0}; /* Default to 0 for PnP */ - struct pnp_dev *dev = pnp_request_card_device(card, card_id->devs[0].id, NULL); - - if(!dev){ - return -EBUSY; - } - - if((scc = kzalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "sb: Error: Could not allocate memory\n"); - return -ENOMEM; - } - - printk(KERN_INFO "sb: PnP: Found Card Named = \"%s\", Card PnP id = " \ - "%s, Device PnP id = %s\n", card->card->name, card_id->id, - dev->id->id); - - scc->card_id = card_id->id; - scc->dev_id = dev->id->id; - sb_dev2cfg(dev, scc); - - printk(KERN_INFO "sb: PnP: Detected at: io=0x%x, irq=%d, " \ - "dma=%d, dma16=%d\n", scc->conf.io_base, scc->conf.irq, - scc->conf.dma, scc->conf.dma2); - - pnp_set_card_drvdata(card, scc); - sb_pnp_devices++; - - return sb_register_oss(scc, &sbmo); -} - -static void sb_pnp_remove(struct pnp_card_link *card) -{ - struct sb_card_config *scc = pnp_get_card_drvdata(card); - - if(!scc) - return; - - printk(KERN_INFO "sb: PnP: Removing %s\n", scc->card_id); - - sb_unload(scc); -} - -static struct pnp_card_driver sb_pnp_driver = { - .name = "OSS SndBlstr", /* 16 character limit */ - .id_table = sb_pnp_card_table, - .probe = sb_pnp_probe, - .remove = sb_pnp_remove, -}; -MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table); -#endif /* CONFIG_PNP */ - -static void sb_unregister_all(void) -{ -#ifdef CONFIG_PNP - if (pnp_registered) - pnp_unregister_card_driver(&sb_pnp_driver); -#endif -} - -static int __init sb_init(void) -{ - int lres = 0; - int pres = 0; - - printk(KERN_INFO "sb: Init: Starting Probe...\n"); - - if(io != -1 && irq != -1 && dma != -1) { - printk(KERN_INFO "sb: Probing legacy card with io=%x, "\ - "irq=%d, dma=%d, dma16=%d\n",io, irq, dma, dma16); - lres = sb_init_legacy(); - } else if((io != -1 || irq != -1 || dma != -1) || - (!pnp && (io == -1 && irq == -1 && dma == -1))) - printk(KERN_ERR "sb: Error: At least io, irq, and dma "\ - "must be set for legacy cards.\n"); - -#ifdef CONFIG_PNP - if(pnp) { - int err = pnp_register_card_driver(&sb_pnp_driver); - if (!err) - pnp_registered = 1; - pres = sb_pnp_devices; - } -#endif - printk(KERN_INFO "sb: Init: Done\n"); - - /* If either PnP or Legacy registered a card then return - * success */ - if (pres == 0 && lres <= 0) { - sb_unregister_all(); - return -ENODEV; - } - return 0; -} - -static void __exit sb_exit(void) -{ - printk(KERN_INFO "sb: Unloading...\n"); - - /* Unload legacy card */ - if (legacy) { - printk (KERN_INFO "sb: Unloading legacy card\n"); - sb_unload(legacy); - } - - sb_unregister_all(); - - vfree(smw_free); - smw_free = NULL; -} - -module_init(sb_init); -module_exit(sb_exit); diff --git a/sound/oss/sb_card.h b/sound/oss/sb_card.h deleted file mode 100644 index 5535cff800df..000000000000 --- a/sound/oss/sb_card.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * sound/oss/sb_card.h - * - * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this - * software for more info. - * - * 02-05-2002 Original Release, Paul Laufer <paul@laufernet.com> - */ - -struct sb_card_config { - struct address_info conf; - struct address_info mpucnf; - const char *card_id; - const char *dev_id; - int mpu; -}; - -#ifdef CONFIG_PNP - -/* - * SoundBlaster PnP tables and structures. - */ - -/* Card PnP ID Table */ -static struct pnp_card_device_id sb_pnp_card_table[] = { - /* Sound Blaster 16 */ - {.id = "CTL0024", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0025", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0026", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0027", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0028", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0029", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL002a", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL002b", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL002c", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL00ed", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster 16 */ - {.id = "CTL0086", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster Vibra16S */ - {.id = "CTL0051", .driver_data = 0, .devs = { {.id="CTL0001"}, } }, - /* Sound Blaster Vibra16C */ - {.id = "CTL0070", .driver_data = 0, .devs = { {.id="CTL0001"}, } }, - /* Sound Blaster Vibra16CL */ - {.id = "CTL0080", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster Vibra16CL */ - {.id = "CTL00F0", .driver_data = 0, .devs = { {.id="CTL0043"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0039", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0042", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0043", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0044", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0045", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0046", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0047", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0048", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL0054", .driver_data = 0, .devs = { {.id="CTL0031"}, } }, - /* Sound Blaster AWE 32 */ - {.id = "CTL009C", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Createive SB32 PnP */ - {.id = "CTL009F", .driver_data = 0, .devs = { {.id="CTL0041"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL009D", .driver_data = 0, .devs = { {.id="CTL0042"}, } }, - /* Sound Blaster AWE 64 Gold */ - {.id = "CTL009E", .driver_data = 0, .devs = { {.id="CTL0044"}, } }, - /* Sound Blaster AWE 64 Gold */ - {.id = "CTL00B2", .driver_data = 0, .devs = { {.id="CTL0044"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C1", .driver_data = 0, .devs = { {.id="CTL0042"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C3", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C5", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00C7", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00E4", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* Sound Blaster AWE 64 */ - {.id = "CTL00E9", .driver_data = 0, .devs = { {.id="CTL0045"}, } }, - /* ESS 1868 */ - {.id = "ESS0968", .driver_data = 0, .devs = { {.id="ESS0968"}, } }, - /* ESS 1868 */ - {.id = "ESS1868", .driver_data = 0, .devs = { {.id="ESS1868"}, } }, - /* ESS 1868 */ - {.id = "ESS1868", .driver_data = 0, .devs = { {.id="ESS8611"}, } }, - /* ESS 1869 PnP AudioDrive */ - {.id = "ESS0003", .driver_data = 0, .devs = { {.id="ESS1869"}, } }, - /* ESS 1869 */ - {.id = "ESS1869", .driver_data = 0, .devs = { {.id="ESS1869"}, } }, - /* ESS 1878 */ - {.id = "ESS1878", .driver_data = 0, .devs = { {.id="ESS1878"}, } }, - /* ESS 1879 */ - {.id = "ESS1879", .driver_data = 0, .devs = { {.id="ESS1879"}, } }, - /* CMI 8330 SoundPRO */ - {.id = "CMI0001", .driver_data = 0, .devs = { {.id="@X@0001"}, - {.id="@H@0001"}, - {.id="@@@0001"}, } }, - /* Diamond DT0197H */ - {.id = "RWR1688", .driver_data = 0, .devs = { {.id="@@@0001"}, - {.id="@X@0001"}, - {.id="@H@0001"}, } }, - /* ALS007 */ - {.id = "ALS0007", .driver_data = 0, .devs = { {.id="@@@0001"}, - {.id="@X@0001"}, - {.id="@H@0001"}, } }, - /* ALS100 */ - {.id = "ALS0001", .driver_data = 0, .devs = { {.id="@@@0001"}, - {.id="@X@0001"}, - {.id="@H@0001"}, } }, - /* ALS110 */ - {.id = "ALS0110", .driver_data = 0, .devs = { {.id="@@@1001"}, - {.id="@X@1001"}, - {.id="@H@0001"}, } }, - /* ALS120 */ - {.id = "ALS0120", .driver_data = 0, .devs = { {.id="@@@2001"}, - {.id="@X@2001"}, - {.id="@H@0001"}, } }, - /* ALS200 */ - {.id = "ALS0200", .driver_data = 0, .devs = { {.id="@@@0020"}, - {.id="@X@0030"}, - {.id="@H@0001"}, } }, - /* ALS200 */ - {.id = "RTL3000", .driver_data = 0, .devs = { {.id="@@@2001"}, - {.id="@X@2001"}, - {.id="@H@0001"}, } }, - /* Sound Blaster 16 (Virtual PC 2004) */ - {.id = "tBA03b0", .driver_data = 0, .devs = { {.id="PNPb003"}, } }, - /* -end- */ - {.id = "", } -}; - -#endif diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c deleted file mode 100644 index 3d50fb4236ed..000000000000 --- a/sound/oss/sb_common.c +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * sound/oss/sb_common.c - * - * Common routines for Sound Blaster compatible cards. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts - * for full duplex support ( only sb16 by now ) - * Rolf Fokkens: Added (BETA?) support for ES1887 chips. - * (fokkensr@vertis.nl) Which means: You can adjust the recording levels. - * - * 2000/01/18 - separated sb_card and sb_common - - * Jeff Garzik <jgarzik@pobox.com> - * - * 2000/09/18 - got rid of attach_uart401 - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - * - * 2001/01/26 - replaced CLI/STI with spinlocks - * Chris Rankin <rankinc@zipworld.com.au> - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/slab.h> - -#include "sound_config.h" -#include "sound_firmware.h" - -#include "mpu401.h" - -#include "sb_mixer.h" -#include "sb.h" -#include "sb_ess.h" - -/* - * global module flag - */ - -int sb_be_quiet; - -static sb_devc *detected_devc; /* For communication from probe to init */ -static sb_devc *last_devc; /* For MPU401 initialization */ - -static unsigned char jazz_irq_bits[] = { - 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 -}; - -static unsigned char jazz_dma_bits[] = { - 0, 1, 0, 2, 0, 3, 0, 4 -}; - -void *smw_free; - -/* - * Jazz16 chipset specific control variables - */ - -static int jazz16_base; /* Not detected */ -static unsigned char jazz16_bits; /* I/O relocation bits */ -static DEFINE_SPINLOCK(jazz16_lock); - -/* - * Logitech Soundman Wave specific initialization code - */ - -#ifdef SMW_MIDI0001_INCLUDED -#include "smw-midi0001.h" -#else -static unsigned char *smw_ucode; -static int smw_ucodeLen; - -#endif - -static sb_devc *last_sb; /* Last sb loaded */ - -int sb_dsp_command(sb_devc * devc, unsigned char val) -{ - int i; - unsigned long limit; - - limit = jiffies + HZ / 10; /* Timeout */ - - /* - * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && (limit-jiffies)>0; i++) - { - if ((inb(DSP_STATUS) & 0x80) == 0) - { - outb((val), DSP_COMMAND); - return 1; - } - } - printk(KERN_WARNING "Sound Blaster: DSP command(%x) timeout.\n", val); - return 0; -} - -int sb_dsp_get_byte(sb_devc * devc) -{ - int i; - - for (i = 1000; i; i--) - { - if (inb(DSP_DATA_AVAIL) & 0x80) - return inb(DSP_READ); - } - return 0xffff; -} - -static void sb_intr (sb_devc *devc) -{ - int status; - unsigned char src = 0xff; - - if (devc->model == MDL_SB16) - { - src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ - - if (src & 4) /* MPU401 interrupt */ - if(devc->midi_irq_cookie) - uart401intr(devc->irq, devc->midi_irq_cookie); - - if (!(src & 3)) - return; /* Not a DSP interrupt */ - } - if (devc->intr_active && (!devc->fullduplex || (src & 0x01))) - { - switch (devc->irq_mode) - { - case IMODE_OUTPUT: - DMAbuf_outputintr(devc->dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr(devc->dev); - break; - - case IMODE_INIT: - break; - - case IMODE_MIDI: - sb_midi_interrupt(devc); - break; - - default: - /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ - ; - } - } - else if (devc->intr_active_16 && (src & 0x02)) - { - switch (devc->irq_mode_16) - { - case IMODE_OUTPUT: - DMAbuf_outputintr(devc->dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr(devc->dev); - break; - - case IMODE_INIT: - break; - - default: - /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ - ; - } - } - /* - * Acknowledge interrupts - */ - - if (src & 0x01) - status = inb(DSP_DATA_AVAIL); - - if (devc->model == MDL_SB16 && src & 0x02) - status = inb(DSP_DATA_AVL16); -} - -static void pci_intr(sb_devc *devc) -{ - int src = inb(devc->pcibase+0x1A); - src&=3; - if(src) - sb_intr(devc); -} - -static irqreturn_t sbintr(int irq, void *dev_id) -{ - sb_devc *devc = dev_id; - - devc->irq_ok = 1; - - switch (devc->model) { - case MDL_ESSPCI: - pci_intr (devc); - break; - - case MDL_ESS: - ess_intr (devc); - break; - default: - sb_intr (devc); - break; - } - return IRQ_HANDLED; -} - -int sb_dsp_reset(sb_devc * devc) -{ - int loopc; - - if (devc->model == MDL_ESS) return ess_dsp_reset (devc); - - /* This is only for non-ESS chips */ - - outb(1, DSP_RESET); - - udelay(10); - outb(0, DSP_RESET); - udelay(30); - - for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++); - - if (inb(DSP_READ) != 0xAA) - { - DDB(printk("sb: No response to RESET\n")); - return 0; /* Sorry */ - } - - return 1; -} - -static void dsp_get_vers(sb_devc * devc) -{ - int i; - - unsigned long flags; - - DDB(printk("Entered dsp_get_vers()\n")); - spin_lock_irqsave(&devc->lock, flags); - devc->major = devc->minor = 0; - sb_dsp_command(devc, 0xe1); /* Get version */ - - for (i = 100000; i; i--) - { - if (inb(DSP_DATA_AVAIL) & 0x80) - { - if (devc->major == 0) - devc->major = inb(DSP_READ); - else - { - devc->minor = inb(DSP_READ); - break; - } - } - } - spin_unlock_irqrestore(&devc->lock, flags); - DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor)); -} - -static int sb16_set_dma_hw(sb_devc * devc) -{ - int bits; - - if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) - { - printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); - return 0; - } - bits = (1 << devc->dma8); - - if (devc->dma16 >= 5 && devc->dma16 <= 7) - bits |= (1 << devc->dma16); - - sb_setmixer(devc, DMA_NR, bits); - return 1; -} - -static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) -{ - /* - * This routine initializes new MIDI port setup register of SB Vibra (CT2502). - */ - unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; - - switch (hw_config->io_base) - { - case 0x300: - sb_setmixer(devc, 0x84, bits | 0x04); - break; - - case 0x330: - sb_setmixer(devc, 0x84, bits | 0x00); - break; - - default: - sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ - printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); - } -} - -static int sb16_set_irq_hw(sb_devc * devc, int level) -{ - int ival; - - switch (level) - { - case 5: - ival = 2; - break; - case 7: - ival = 4; - break; - case 9: - ival = 1; - break; - case 10: - ival = 8; - break; - default: - printk(KERN_ERR "SB16: Invalid IRQ%d\n", level); - return 0; - } - sb_setmixer(devc, IRQ_NR, ival); - return 1; -} - -static void relocate_Jazz16(sb_devc * devc, struct address_info *hw_config) -{ - unsigned char bits = 0; - unsigned long flags; - - if (jazz16_base != 0 && jazz16_base != hw_config->io_base) - return; - - switch (hw_config->io_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - default: - return; - } - bits = jazz16_bits = bits << 5; - jazz16_base = hw_config->io_base; - - /* - * Magic wake up sequence by writing to 0x201 (aka Joystick port) - */ - spin_lock_irqsave(&jazz16_lock, flags); - outb((0xAF), 0x201); - outb((0x50), 0x201); - outb((bits), 0x201); - spin_unlock_irqrestore(&jazz16_lock, flags); -} - -static int init_Jazz16(sb_devc * devc, struct address_info *hw_config) -{ - char name[100]; - /* - * First try to check that the card has Jazz16 chip. It identifies itself - * by returning 0x12 as response to DSP command 0xfa. - */ - - if (!sb_dsp_command(devc, 0xfa)) - return 0; - - if (sb_dsp_get_byte(devc) != 0x12) - return 0; - - /* - * OK so far. Now configure the IRQ and DMA channel used by the card. - */ - if (hw_config->irq < 1 || hw_config->irq > 15 || jazz_irq_bits[hw_config->irq] == 0) - { - printk(KERN_ERR "Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); - return 0; - } - if (hw_config->dma < 0 || hw_config->dma > 3 || jazz_dma_bits[hw_config->dma] == 0) - { - printk(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); - return 0; - } - if (hw_config->dma2 < 0) - { - printk(KERN_ERR "Jazz16: No 16 bit DMA channel defined\n"); - return 0; - } - if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || jazz_dma_bits[hw_config->dma2] == 0) - { - printk(KERN_ERR "Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); - return 0; - } - devc->dma16 = hw_config->dma2; - - if (!sb_dsp_command(devc, 0xfb)) - return 0; - - if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] | - (jazz_dma_bits[hw_config->dma2] << 4))) - return 0; - - if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq])) - return 0; - - /* - * Now we have configured a standard Jazz16 device. - */ - devc->model = MDL_JAZZ; - strcpy(name, "Jazz16"); - - hw_config->name = "Jazz16"; - devc->caps |= SB_NO_MIDI; - return 1; -} - -static void relocate_ess1688(sb_devc * devc) -{ - unsigned char bits; - - switch (devc->base) - { - case 0x220: - bits = 0x04; - break; - case 0x230: - bits = 0x05; - break; - case 0x240: - bits = 0x06; - break; - case 0x250: - bits = 0x07; - break; - default: - return; /* Wrong port */ - } - - DDB(printk("Doing ESS1688 address selection\n")); - - /* - * ES1688 supports two alternative ways for software address config. - * First try the so called Read-Sequence-Key method. - */ - - /* Reset the sequence logic */ - inb(0x229); - inb(0x229); - inb(0x229); - - /* Perform the read sequence */ - inb(0x22b); - inb(0x229); - inb(0x22b); - inb(0x229); - inb(0x229); - inb(0x22b); - inb(0x229); - - /* Select the base address by reading from it. Then probe using the port. */ - inb(devc->base); - if (sb_dsp_reset(devc)) /* Bingo */ - return; - -#if 0 /* This causes system lockups (Nokia 386/25 at least) */ - /* - * The last resort is the system control register method. - */ - - outb((0x00), 0xfb); /* 0xFB is the unlock register */ - outb((0x00), 0xe0); /* Select index 0 */ - outb((bits), 0xe1); /* Write the config bits */ - outb((0x00), 0xf9); /* 0xFB is the lock register */ -#endif -} - -int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo) -{ - sb_devc sb_info; - sb_devc *devc = &sb_info; - - memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ - - /* Copy module options in place */ - if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options)); - - sb_info.my_mididev = -1; - sb_info.my_mixerdev = -1; - sb_info.dev = -1; - - /* - * Initialize variables - */ - - DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base)); - - spin_lock_init(&devc->lock); - devc->type = hw_config->card_subtype; - - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma8 = hw_config->dma; - - devc->dma16 = -1; - devc->pcibase = pciio; - - if(pci == SB_PCI_ESSMAESTRO) - { - devc->model = MDL_ESSPCI; - devc->caps |= SB_PCI_IRQ; - hw_config->driver_use_1 |= SB_PCI_IRQ; - hw_config->card_subtype = MDL_ESSPCI; - } - - if(pci == SB_PCI_YAMAHA) - { - devc->model = MDL_YMPCI; - devc->caps |= SB_PCI_IRQ; - hw_config->driver_use_1 |= SB_PCI_IRQ; - hw_config->card_subtype = MDL_YMPCI; - - printk("Yamaha PCI mode.\n"); - } - - if (devc->sbmo.acer) - { - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - inb(devc->base + 0x09); - inb(devc->base + 0x09); - inb(devc->base + 0x09); - inb(devc->base + 0x0b); - inb(devc->base + 0x09); - inb(devc->base + 0x0b); - inb(devc->base + 0x09); - inb(devc->base + 0x09); - inb(devc->base + 0x0b); - inb(devc->base + 0x09); - inb(devc->base + 0x00); - spin_unlock_irqrestore(&devc->lock, flags); - } - /* - * Detect the device - */ - - if (sb_dsp_reset(devc)) - dsp_get_vers(devc); - else - devc->major = 0; - - if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) - if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) - relocate_Jazz16(devc, hw_config); - - if (devc->major == 0 && (devc->type == MDL_ESS || devc->type == 0)) - relocate_ess1688(devc); - - if (!sb_dsp_reset(devc)) - { - DDB(printk("SB reset failed\n")); -#ifdef MODULE - printk(KERN_INFO "sb: dsp reset failed.\n"); -#endif - return 0; - } - if (devc->major == 0) - dsp_get_vers(devc); - - if (devc->major == 3 && devc->minor == 1) - { - if (devc->type == MDL_AZTECH) /* SG Washington? */ - { - if (sb_dsp_command(devc, 0x09)) - if (sb_dsp_command(devc, 0x00)) /* Enter WSS mode */ - { - int i; - - /* Have some delay */ - for (i = 0; i < 10000; i++) - inb(DSP_DATA_AVAIL); - devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ - devc->model = MDL_AZTECH; - } - } - } - - if(devc->type == MDL_ESSPCI) - devc->model = MDL_ESSPCI; - - if(devc->type == MDL_YMPCI) - { - printk("YMPCI selected\n"); - devc->model = MDL_YMPCI; - } - - /* - * Save device information for sb_dsp_init() - */ - - - detected_devc = kmemdup(devc, sizeof(sb_devc), GFP_KERNEL); - if (detected_devc == NULL) - { - printk(KERN_ERR "sb: Can't allocate memory for device information\n"); - return 0; - } - MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); - return 1; -} - -int sb_dsp_init(struct address_info *hw_config, struct module *owner) -{ - sb_devc *devc; - char name[100]; - extern int sb_be_quiet; - int mixer22, mixer30; - -/* - * Check if we had detected a SB device earlier - */ - DDB(printk("sb_dsp_init(%x) entered\n", hw_config->io_base)); - name[0] = 0; - - if (detected_devc == NULL) - { - MDB(printk("No detected device\n")); - return 0; - } - devc = detected_devc; - detected_devc = NULL; - - if (devc->base != hw_config->io_base) - { - DDB(printk("I/O port mismatch\n")); - release_region(devc->base, 16); - return 0; - } - /* - * Now continue initialization of the device - */ - - devc->caps = hw_config->driver_use_1; - - if (!((devc->caps & SB_NO_AUDIO) && (devc->caps & SB_NO_MIDI)) && hw_config->irq > 0) - { /* IRQ setup */ - - /* - * ESS PCI cards do shared PCI IRQ stuff. Since they - * will get shared PCI irq lines we must cope. - */ - - int i=(devc->caps&SB_PCI_IRQ)?IRQF_SHARED:0; - - if (request_irq(hw_config->irq, sbintr, i, "soundblaster", devc) < 0) - { - printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); - release_region(devc->base, 16); - return 0; - } - devc->irq_ok = 0; - - if (devc->major == 4) - if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ - { - free_irq(devc->irq, devc); - release_region(devc->base, 16); - return 0; - } - if ((devc->type == 0 || devc->type == MDL_ESS) && - devc->major == 3 && devc->minor == 1) - { /* Handle various chipsets which claim they are SB Pro compatible */ - if ((devc->type != 0 && devc->type != MDL_ESS) || - !ess_init(devc, hw_config)) - { - if ((devc->type != 0 && devc->type != MDL_JAZZ && - devc->type != MDL_SMW) || !init_Jazz16(devc, hw_config)) - { - DDB(printk("This is a genuine SB Pro\n")); - } - } - } - if (devc->major == 4 && devc->minor <= 11 ) /* Won't work */ - devc->irq_ok = 1; - else - { - int n; - - for (n = 0; n < 3 && devc->irq_ok == 0; n++) - { - if (sb_dsp_command(devc, 0xf2)) /* Cause interrupt immediately */ - { - int i; - - for (i = 0; !devc->irq_ok && i < 10000; i++); - } - } - if (!devc->irq_ok) - printk(KERN_WARNING "sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); - else - { - DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq)); - } - } - } /* IRQ setup */ - - last_sb = devc; - - switch (devc->major) - { - case 1: /* SB 1.0 or 1.5 */ - devc->model = hw_config->card_subtype = MDL_SB1; - break; - - case 2: /* SB 2.x */ - if (devc->minor == 0) - devc->model = hw_config->card_subtype = MDL_SB2; - else - devc->model = hw_config->card_subtype = MDL_SB201; - break; - - case 3: /* SB Pro and most clones */ - switch (devc->model) { - case 0: - devc->model = hw_config->card_subtype = MDL_SBPRO; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; - break; - case MDL_ESS: - ess_dsp_init(devc, hw_config); - break; - } - break; - - case 4: - devc->model = hw_config->card_subtype = MDL_SB16; - /* - * ALS007 and ALS100 return DSP version 4.2 and have 2 post-reset !=0 - * registers at 0x3c and 0x4c (output ctrl registers on ALS007) whereas - * a "standard" SB16 doesn't have a register at 0x4c. ALS100 actively - * updates register 0x22 whenever 0x30 changes, as per the SB16 spec. - * Since ALS007 doesn't, this can be used to differentiate the 2 cards. - */ - if ((devc->minor == 2) && sb_getmixer(devc,0x3c) && sb_getmixer(devc,0x4c)) - { - mixer30 = sb_getmixer(devc,0x30); - sb_setmixer(devc,0x22,(mixer22=sb_getmixer(devc,0x22)) & 0x0f); - sb_setmixer(devc,0x30,0xff); - /* ALS100 will force 0x30 to 0xf8 like SB16; ALS007 will allow 0xff. */ - /* Register 0x22 & 0xf0 on ALS100 == 0xf0; on ALS007 it == 0x10. */ - if ((sb_getmixer(devc,0x30) != 0xff) || ((sb_getmixer(devc,0x22) & 0xf0) != 0x10)) - { - devc->submodel = SUBMDL_ALS100; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16 (ALS-100)"; - } - else - { - sb_setmixer(devc,0x3c,0x1f); /* Enable all inputs */ - sb_setmixer(devc,0x4c,0x1f); - sb_setmixer(devc,0x22,mixer22); /* Restore 0x22 to original value */ - devc->submodel = SUBMDL_ALS007; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16 (ALS-007)"; - } - sb_setmixer(devc,0x30,mixer30); - } - else if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16"; - - if (hw_config->dma2 == -1) - devc->dma16 = devc->dma8; - else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) - { - printk(KERN_WARNING "SB16: Bad or missing 16 bit DMA channel\n"); - devc->dma16 = devc->dma8; - } - else - devc->dma16 = hw_config->dma2; - - if(!sb16_set_dma_hw(devc)) { - free_irq(devc->irq, devc); - release_region(hw_config->io_base, 16); - return 0; - } - - devc->caps |= SB_NO_MIDI; - } - - if (!(devc->caps & SB_NO_MIXER)) - if (devc->major == 3 || devc->major == 4) - sb_mixer_init(devc, owner); - - if (!(devc->caps & SB_NO_MIDI)) - sb_dsp_midi_init(devc, owner); - - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; - - sprintf(name, "%s (%d.%02d)", hw_config->name, devc->major, devc->minor); - conf_printf(name, hw_config); - - /* - * Assuming that a sound card is Sound Blaster (compatible) is the most common - * configuration error and the mother of all problems. Usually sound cards - * emulate SB Pro but in addition they have a 16 bit native mode which should be - * used in Unix. See Readme.cards for more information about configuring OSS/Free - * properly. - */ - if (devc->model <= MDL_SBPRO) - { - if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1 (rare ones may have 3.2). */ - { - printk(KERN_INFO "This sound card may not be fully Sound Blaster Pro compatible.\n"); - printk(KERN_INFO "In many cases there is another way to configure OSS so that\n"); - printk(KERN_INFO "it works properly with OSS (for example in 16 bit mode).\n"); - printk(KERN_INFO "Please ignore this message if you _really_ have a SB Pro.\n"); - } - else if (!sb_be_quiet && devc->model == MDL_SBPRO) - { - printk(KERN_INFO "SB DSP version is just %d.%02d which means that your card is\n", devc->major, devc->minor); - printk(KERN_INFO "several years old (8 bit only device) or alternatively the sound driver\n"); - printk(KERN_INFO "is incorrectly configured.\n"); - } - } - hw_config->card_subtype = devc->model; - hw_config->slots[0]=devc->dev; - last_devc = devc; /* For SB MPU detection */ - - if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) - { - if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) - { - printk(KERN_WARNING "Sound Blaster: Can't allocate 8 bit DMA channel %d\n", devc->dma8); - } - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - { - if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) - printk(KERN_WARNING "Sound Blaster: can't allocate 16 bit DMA channel %d.\n", devc->dma16); - } - sb_audio_init(devc, name, owner); - hw_config->slots[0]=devc->dev; - } - else - { - MDB(printk("Sound Blaster: no audio devices found.\n")); - } - return 1; -} - -/* if (sbmpu) below we allow mpu401 to manage the midi devs - otherwise we have to unload them. (Andrzej Krzysztofowicz) */ - -void sb_dsp_unload(struct address_info *hw_config, int sbmpu) -{ - sb_devc *devc; - - devc = audio_devs[hw_config->slots[0]]->devc; - - if (devc && devc->base == hw_config->io_base) - { - if ((devc->model & MDL_ESS) && devc->pcibase) - release_region(devc->pcibase, 8); - - release_region(devc->base, 16); - - if (!(devc->caps & SB_NO_AUDIO)) - { - sound_free_dma(devc->dma8); - if (devc->dma16 >= 0) - sound_free_dma(devc->dma16); - } - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI)) - { - if (devc->irq > 0) - free_irq(devc->irq, devc); - - sb_mixer_unload(devc); - /* We don't have to do this bit any more the UART401 is its own - master -- Krzysztof Halasa */ - /* But we have to do it, if UART401 is not detected */ - if (!sbmpu) - sound_unload_mididev(devc->my_mididev); - sound_unload_audiodev(devc->dev); - } - kfree(devc); - } - else - release_region(hw_config->io_base, 16); - - kfree(detected_devc); -} - -/* - * Mixer access routines - * - * ES1887 modifications: some mixer registers reside in the - * range above 0xa0. These must be accessed in another way. - */ - -void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) -{ - unsigned long flags; - - if (devc->model == MDL_ESS) { - ess_setmixer (devc, port, value); - return; - } - - spin_lock_irqsave(&devc->lock, flags); - - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - udelay(20); - outb(((unsigned char) (value & 0xff)), MIXER_DATA); - udelay(20); - - spin_unlock_irqrestore(&devc->lock, flags); -} - -unsigned int sb_getmixer(sb_devc * devc, unsigned int port) -{ - unsigned int val; - unsigned long flags; - - if (devc->model == MDL_ESS) return ess_getmixer (devc, port); - - spin_lock_irqsave(&devc->lock, flags); - - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - udelay(20); - val = inb(MIXER_DATA); - udelay(20); - - spin_unlock_irqrestore(&devc->lock, flags); - - return val; -} - -void sb_chgmixer - (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val) -{ - int value; - - value = sb_getmixer(devc, reg); - value = (value & ~mask) | (val & mask); - sb_setmixer(devc, reg, value); -} - -/* - * MPU401 MIDI initialization. - */ - -static void smw_putmem(sb_devc * devc, int base, int addr, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&jazz16_lock, flags); /* NOT the SB card? */ - - outb((addr & 0xff), base + 1); /* Low address bits */ - outb((addr >> 8), base + 2); /* High address bits */ - outb((val), base); /* Data */ - - spin_unlock_irqrestore(&jazz16_lock, flags); -} - -static unsigned char smw_getmem(sb_devc * devc, int base, int addr) -{ - unsigned long flags; - unsigned char val; - - spin_lock_irqsave(&jazz16_lock, flags); /* NOT the SB card? */ - - outb((addr & 0xff), base + 1); /* Low address bits */ - outb((addr >> 8), base + 2); /* High address bits */ - val = inb(base); /* Data */ - - spin_unlock_irqrestore(&jazz16_lock, flags); - return val; -} - -static int smw_midi_init(sb_devc * devc, struct address_info *hw_config) -{ - int mpu_base = hw_config->io_base; - int mp_base = mpu_base + 4; /* Microcontroller base */ - int i; - unsigned char control; - - - /* - * Reset the microcontroller so that the RAM can be accessed - */ - - control = inb(mpu_base + 7); - outb((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */ - outb(((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */ - - mdelay(3); /* Wait at least 1ms */ - - outb((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ - - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem(devc, mp_base, 0, 0x00); - smw_putmem(devc, mp_base, 1, 0xff); - udelay(10); - - if (smw_getmem(devc, mp_base, 0) != 0x00 || smw_getmem(devc, mp_base, 1) != 0xff) - { - DDB(printk("SM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(devc, mp_base, 0), smw_getmem(devc, mp_base, 1))); - return 0; /* No RAM */ - } - /* - * There is RAM so assume it's really a SM Wave - */ - - devc->model = MDL_SMW; - smw_mixer_init(devc); - -#ifdef MODULE - if (!smw_ucode) - { - smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); - smw_free = smw_ucode; - } -#endif - if (smw_ucodeLen > 0) - { - if (smw_ucodeLen != 8192) - { - printk(KERN_ERR "SM Wave: Invalid microcode (MIDI0001.BIN) length\n"); - return 1; - } - /* - * Download microcode - */ - - for (i = 0; i < 8192; i++) - smw_putmem(devc, mp_base, i, smw_ucode[i]); - - /* - * Verify microcode - */ - - for (i = 0; i < 8192; i++) - if (smw_getmem(devc, mp_base, i) != smw_ucode[i]) - { - printk(KERN_ERR "SM Wave: Microcode verification failed\n"); - return 0; - } - } - control = 0; -#ifdef SMW_SCSI_IRQ - /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * FIXME - make this a module option - * - * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. - */ - { - static unsigned char scsi_irq_bits[] = { - 0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0 - }; - control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; - } -#endif - -#ifdef SMW_OPL4_ENABLE - /* - * Make the OPL4 chip visible on the PC bus at 0x380. - * - * There is no need to enable this feature since this driver - * doesn't support OPL4 yet. Also there is no RAM in SM Wave so - * enabling OPL4 is pretty useless. - */ - control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ - /* control |= 0x20; Uncomment this if you want to use IRQ7 */ -#endif - outb((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ - hw_config->name = "SoundMan Wave"; - return 1; -} - -static int init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config) -{ - int mpu_base = hw_config->io_base; - int sb_base = devc->base; - int irq = hw_config->irq; - - unsigned char bits = 0; - unsigned long flags; - - if (irq < 0) - irq *= -1; - - if (irq < 1 || irq > 15 || - jazz_irq_bits[irq] == 0) - { - printk(KERN_ERR "Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); - return 0; - } - switch (sb_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - default: - return 0; - } - bits = jazz16_bits = bits << 5; - switch (mpu_base) - { - case 0x310: - bits |= 1; - break; - case 0x320: - bits |= 2; - break; - case 0x330: - bits |= 3; - break; - default: - printk(KERN_ERR "Jazz16: Invalid MIDI I/O port %x\n", mpu_base); - return 0; - } - /* - * Magic wake up sequence by writing to 0x201 (aka Joystick port) - */ - spin_lock_irqsave(&jazz16_lock, flags); - outb(0xAF, 0x201); - outb(0x50, 0x201); - outb(bits, 0x201); - spin_unlock_irqrestore(&jazz16_lock, flags); - - hw_config->name = "Jazz16"; - smw_midi_init(devc, hw_config); - - if (!sb_dsp_command(devc, 0xfb)) - return 0; - - if (!sb_dsp_command(devc, jazz_dma_bits[devc->dma8] | - (jazz_dma_bits[devc->dma16] << 4))) - return 0; - - if (!sb_dsp_command(devc, jazz_irq_bits[devc->irq] | - (jazz_irq_bits[irq] << 4))) - return 0; - - return 1; -} - -int probe_sbmpu(struct address_info *hw_config, struct module *owner) -{ - sb_devc *devc = last_devc; - int ret; - - if (last_devc == NULL) - return 0; - - last_devc = NULL; - - if (hw_config->io_base <= 0) - { - /* The real vibra16 is fine about this, but we have to go - wipe up after Cyrix again */ - - if(devc->model == MDL_SB16 && devc->minor >= 12) - { - unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; - sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ - } - return 0; - } - -#if defined(CONFIG_SOUND_MPU401) - if (devc->model == MDL_ESS) - { - struct resource *ports; - ports = request_region(hw_config->io_base, 2, "mpu401"); - if (!ports) { - printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - if (!ess_midi_init(devc, hw_config)) { - release_region(hw_config->io_base, 2); - return 0; - } - hw_config->name = "ESS1xxx MPU"; - devc->midi_irq_cookie = NULL; - if (!probe_mpu401(hw_config, ports)) { - release_region(hw_config->io_base, 2); - return 0; - } - attach_mpu401(hw_config, owner); - if (last_sb->irq == -hw_config->irq) - last_sb->midi_irq_cookie = - (void *)(long) hw_config->slots[1]; - return 1; - } -#endif - - switch (devc->model) - { - case MDL_SB16: - if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) - { - printk(KERN_ERR "SB16: Invalid MIDI port %x\n", hw_config->io_base); - return 0; - } - hw_config->name = "Sound Blaster 16"; - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (devc->minor > 12) /* What is Vibra's version??? */ - sb16_set_mpu_port(devc, hw_config); - break; - - case MDL_JAZZ: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!init_Jazz16_midi(devc, hw_config)) - return 0; - break; - - case MDL_YMPCI: - hw_config->name = "Yamaha PCI Legacy"; - printk("Yamaha PCI legacy UART401 check.\n"); - break; - default: - return 0; - } - - ret = probe_uart401(hw_config, owner); - if (ret) - last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; - return ret; -} - -void unload_sbmpu(struct address_info *hw_config) -{ -#if defined(CONFIG_SOUND_MPU401) - if (!strcmp (hw_config->name, "ESS1xxx MPU")) { - unload_mpu401(hw_config); - return; - } -#endif - unload_uart401(hw_config); -} - -EXPORT_SYMBOL(sb_dsp_init); -EXPORT_SYMBOL(sb_dsp_detect); -EXPORT_SYMBOL(sb_dsp_unload); -EXPORT_SYMBOL(sb_be_quiet); -EXPORT_SYMBOL(probe_sbmpu); -EXPORT_SYMBOL(unload_sbmpu); -EXPORT_SYMBOL(smw_free); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c deleted file mode 100644 index 17e3f14318cd..000000000000 --- a/sound/oss/sb_ess.c +++ /dev/null @@ -1,1823 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#undef FKS_LOGGING -#undef FKS_TEST - -/* - * tabs should be 4 spaces, in vi(m): set tabstop=4 - * - * TODO: consistency speed calculations!! - * cleanup! - * ????: Did I break MIDI support? - * - * History: - * - * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per - * fokkensr@vertis.nl input basis. - * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, - * ES1868, ES1869 and ES1878. Could be used for - * specific handling in the future. All except - * ES1887 and ES1888 and ES688 are handled like - * ES1688. - * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now - * have the "Dec 20" support + RECLEV - * (Jan 2 1999): Preparation for Full Duplex. This means - * Audio 2 is now used for playback when dma16 - * is specified. The next step would be to use - * Audio 1 and Audio 2 at the same time. - * (Jan 9 1999): Put all ESS stuff into sb_ess.[ch], this - * includes both the ESS stuff that has been in - * sb_*[ch] before I touched it and the ESS support - * I added later - * (Jan 23 1999): Full Duplex seems to work. I wrote a small - * test proggy which works OK. Haven't found - * any applications to test it though. So why did - * I bother to create it anyway?? :) Just for - * fun. - * (May 2 1999): I tried to be too smart by "introducing" - * ess_calc_best_speed (). The idea was that two - * dividers could be used to setup a samplerate, - * ess_calc_best_speed () would choose the best. - * This works for playback, but results in - * recording problems for high samplerates. I - * fixed this by removing ess_calc_best_speed () - * and just doing what the documentation says. - * Andy Sloane (Jun 4 1999): Stole some code from ALSA to fix the playback - * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. - * 1879's were previously ignored by this driver; - * added (untested) support for those. - * Cvetan Ivanov (Oct 27 1999): Fixed ess_dsp_init to call ess_set_dma_hw for - * zezo@inet.bg _ALL_ ESS models, not only ES1887 - * - * This files contains ESS chip specifics. It's based on the existing ESS - * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This - * file adds features like: - * - Chip Identification (as shown in /proc/sound) - * - RECLEV support for ES1688 and later - * - 6 bits playback level support chips later than ES1688 - * - Recording level support on a per-device basis for ES1887 - * - Full-Duplex for ES1887 - * - * Full duplex is enabled by specifying dma16. While the normal dma must - * be one of 0, 1 or 3, dma16 can be one of 0, 1, 3 or 5. DMA 5 is a 16 bit - * DMA channel, while the others are 8 bit.. - * - * ESS detection isn't full proof (yet). If it fails an additional module - * parameter esstype can be specified to be one of the following: - * -1, 0, 688, 1688, 1868, 1869, 1788, 1887, 1888 - * -1 means: mimic 2.0 behaviour, - * 0 means: auto detect. - * others: explicitly specify chip - * -1 is default, cause auto detect still doesn't work. - */ - -/* - * About the documentation - * - * I don't know if the chips all are OK, but the documentation is buggy. 'cause - * I don't have all the cips myself, there's a lot I cannot verify. I'll try to - * keep track of my latest insights about his here. If you have additional info, - * please enlighten me (fokkensr@vertis.nl)! - * - * I had the impression that ES1688 also has 6 bit master volume control. The - * documentation about ES1888 (rev C, october '95) claims that ES1888 has - * the following features ES1688 doesn't have: - * - 6 bit master volume - * - Full Duplex - * So ES1688 apparently doesn't have 6 bit master volume control, but the - * ES1688 does have RECLEV control. Makes me wonder: does ES688 have it too? - * Without RECLEV ES688 won't be much fun I guess. - * - * From the ES1888 (rev C, october '95) documentation I got the impression - * that registers 0x68 to 0x6e don't exist which means: no recording volume - * controls. To my surprise the ES888 documentation (1/14/96) claims that - * ES888 does have these record mixer registers, but that ES1888 doesn't have - * 0x69 and 0x6b. So the rest should be there. - * - * I'm trying to get ES1887 Full Duplex. Audio 2 is playback only, while Audio 2 - * is both record and playback. I think I should use Audio 2 for all playback. - * - * The documentation is an adventure: it's close but not fully accurate. I - * found out that after a reset some registers are *NOT* reset, though the - * docs say the would be. Interesting ones are 0x7f, 0x7d and 0x7a. They are - * related to the Audio 2 channel. I also was surprised about the consequences - * of writing 0x00 to 0x7f (which should be done by reset): The ES1887 moves - * into ES1888 mode. This means that it claims IRQ 11, which happens to be my - * ISDN adapter. Needless to say it no longer worked. I now understand why - * after rebooting 0x7f already was 0x05, the value of my choice: the BIOS - * did it. - * - * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is - * described as if it's exactly the same as register 0xa1. This is *NOT* true. - * The description of 0x70 in ES1869 docs is accurate however. - * Well, the assumption about ES1869 was wrong: register 0x70 is very much - * like register 0xa1, except that bit 7 is always 1, whatever you want - * it to be. - * - * When using audio 2 mixer register 0x72 seems te be meaningless. Only 0xa2 - * has effect. - * - * Software reset not being able to reset all registers is great! Especially - * the fact that register 0x78 isn't reset is great when you wanna change back - * to single dma operation (simplex): audio 2 is still operational, and uses - * the same dma as audio 1: your ess changes into a funny echo machine. - * - * Received the news that ES1688 is detected as a ES1788. Did some thinking: - * the ES1887 detection scheme suggests in step 2 to try if bit 3 of register - * 0x64 can be changed. This is inaccurate, first I inverted the * check: "If - * can be modified, it's a 1688", which lead to a correct detection - * of my ES1887. It resulted however in bad detection of 1688 (reported by mail) - * and 1868 (if no PnP detection first): they result in a 1788 being detected. - * I don't have docs on 1688, but I do have docs on 1868: The documentation is - * probably inaccurate in the fact that I should check bit 2, not bit 3. This - * is what I do now. - */ - -/* - * About recognition of ESS chips - * - * The distinction of ES688, ES1688, ES1788, ES1887 and ES1888 is described in - * a (preliminary ??) datasheet on ES1887. Its aim is to identify ES1887, but - * during detection the text claims that "this chip may be ..." when a step - * fails. This scheme is used to distinct between the above chips. - * It appears however that some PnP chips like ES1868 are recognized as ES1788 - * by the ES1887 detection scheme. These PnP chips can be detected in another - * way however: ES1868, ES1869 and ES1878 can be recognized (full proof I think) - * by repeatedly reading mixer register 0x40. This is done by ess_identify in - * sb_common.c. - * This results in the following detection steps: - * - distinct between ES688 and ES1688+ (as always done in this driver) - * if ES688 we're ready - * - try to detect ES1868, ES1869 or ES1878 - * if successful we're ready - * - try to detect ES1888, ES1887 or ES1788 - * if successful we're ready - * - Dunno. Must be 1688. Will do in general - * - * About RECLEV support: - * - * The existing ES1688 support didn't take care of the ES1688+ recording - * levels very well. Whenever a device was selected (recmask) for recording - * its recording level was loud, and it couldn't be changed. The fact that - * internal register 0xb4 could take care of RECLEV, didn't work meaning until - * its value was restored every time the chip was reset; this reset the - * value of 0xb4 too. I guess that's what 4front also had (have?) trouble with. - * - * About ES1887 support: - * - * The ES1887 has separate registers to control the recording levels, for all - * inputs. The ES1887 specific software makes these levels the same as their - * corresponding playback levels, unless recmask says they aren't recorded. In - * the latter case the recording volumes are 0. - * Now recording levels of inputs can be controlled, by changing the playback - * levels. Furthermore several devices can be recorded together (which is not - * possible with the ES1688). - * Besides the separate recording level control for each input, the common - * recording level can also be controlled by RECLEV as described above. - * - * Not only ES1887 have this recording mixer. I know the following from the - * documentation: - * ES688 no - * ES1688 no - * ES1868 no - * ES1869 yes - * ES1878 no - * ES1879 yes - * ES1888 no/yes Contradicting documentation; most recent: yes - * ES1946 yes This is a PCI chip; not handled by this driver - */ - -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> - -#include "sound_config.h" -#include "sb_mixer.h" -#include "sb.h" - -#include "sb_ess.h" - -#define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ -#define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ - -#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ -#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ -#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ -#define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ -#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */ -#define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ -#define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ - -#define SB_CAP_ES18XX_RATE 0x100 - -#define ES1688_CLOCK1 795444 /* 128 - div */ -#define ES1688_CLOCK2 397722 /* 256 - div */ -#define ES18XX_CLOCK1 793800 /* 128 - div */ -#define ES18XX_CLOCK2 768000 /* 256 - div */ - -#ifdef FKS_LOGGING -static void ess_show_mixerregs (sb_devc *devc); -#endif -static int ess_read (sb_devc * devc, unsigned char reg); -static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data); -static void ess_chgmixer - (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val); - -/**************************************************************************** - * * - * ESS audio * - * * - ****************************************************************************/ - -struct ess_command {short cmd; short data;}; - -/* - * Commands for initializing Audio 1 for input (record) - */ -static struct ess_command ess_i08m[] = /* input 8 bit mono */ - { {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; -static struct ess_command ess_i16m[] = /* input 16 bit mono */ - { {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; -static struct ess_command ess_i08s[] = /* input 8 bit stereo */ - { {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; -static struct ess_command ess_i16s[] = /* input 16 bit stereo */ - { {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; - -static struct ess_command *ess_inp_cmds[] = - { ess_i08m, ess_i16m, ess_i08s, ess_i16s }; - - -/* - * Commands for initializing Audio 1 for output (playback) - */ -static struct ess_command ess_o08m[] = /* output 8 bit mono */ - { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; -static struct ess_command ess_o16m[] = /* output 16 bit mono */ - { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; -static struct ess_command ess_o08s[] = /* output 8 bit stereo */ - { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; -static struct ess_command ess_o16s[] = /* output 16 bit stereo */ - { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; - -static struct ess_command *ess_out_cmds[] = - { ess_o08m, ess_o16m, ess_o08s, ess_o16s }; - -static void ess_exec_commands - (sb_devc *devc, struct ess_command *cmdtab[]) -{ - struct ess_command *cmd; - - cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ]; - - while (cmd->cmd != -1) { - ess_write (devc, cmd->cmd, cmd->data); - cmd++; - } -} - -static void ess_change - (sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val) -{ - int value; - - value = ess_read (devc, reg); - value = (value & ~mask) | (val & mask); - ess_write (devc, reg, value); -} - -static void ess_set_output_parms - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (devc->duplex) { - devc->trg_buf_16 = buf; - devc->trg_bytes_16 = nr_bytes; - devc->trg_intrflag_16 = intrflag; - devc->irq_mode_16 = IMODE_OUTPUT; - } else { - devc->trg_buf = buf; - devc->trg_bytes = nr_bytes; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_OUTPUT; - } -} - -static void ess_set_input_parms - (int dev, unsigned long buf, int count, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; -} - -static int ess_calc_div (int clock, int revert, int *speedp, int *diffp) -{ - int divider; - int speed, diff; - int retval; - - speed = *speedp; - divider = (clock + speed / 2) / speed; - retval = revert - divider; - if (retval > revert - 1) { - retval = revert - 1; - divider = revert - retval; - } - /* This line is suggested. Must be wrong I think - *speedp = (clock + divider / 2) / divider; - So I chose the next one */ - - *speedp = clock / divider; - diff = speed - *speedp; - if (diff < 0) diff =-diff; - *diffp = diff; - - return retval; -} - -static int ess_calc_best_speed - (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) -{ - int speed1 = *speedp, speed2 = *speedp; - int div1, div2; - int diff1, diff2; - int retval; - - div1 = ess_calc_div (clock1, rev1, &speed1, &diff1); - div2 = ess_calc_div (clock2, rev2, &speed2, &diff2); - - if (diff1 < diff2) { - *divp = div1; - *speedp = speed1; - retval = 1; - } else { - /* *divp = div2; */ - *divp = 0x80 | div2; - *speedp = speed2; - retval = 2; - } - - return retval; -} - -/* - * Depending on the audiochannel ESS devices can - * have different clock settings. These are made consistent for duplex - * however. - * callers of ess_speed only do an audionum suggestion, which means - * input suggests 1, output suggests 2. This suggestion is only true - * however when doing duplex. - */ -static void ess_common_speed (sb_devc *devc, int *speedp, int *divp) -{ - int diff = 0, div; - - if (devc->duplex) { - /* - * The 0x80 is important for the first audio channel - */ - if (devc->submodel == SUBMDL_ES1888) { - div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); - } else { - div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); - } - } else if(devc->caps & SB_CAP_ES18XX_RATE) { - if (devc->submodel == SUBMDL_ES1888) { - ess_calc_best_speed(397700, 128, 795500, 256, - &div, speedp); - } else { - ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, - &div, speedp); - } - } else { - if (*speedp > 22000) { - div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff); - } else { - div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff); - } - } - *divp = div; -} - -static void ess_speed (sb_devc *devc, int audionum) -{ - int speed; - int div, div2; - - ess_common_speed (devc, &(devc->speed), &div); - -#ifdef FKS_REG_LOGGING -printk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc->speed, div); -#endif - - /* Set filter roll-off to 90% of speed/2 */ - speed = (devc->speed * 9) / 20; - - div2 = 256 - 7160000 / (speed * 82); - - if (!devc->duplex) audionum = 1; - - if (audionum == 1) { - /* Change behaviour of register A1 * - sb_chg_mixer(devc, 0x71, 0x20, 0x20) - * For ES1869 only??? */ - ess_write (devc, 0xa1, div); - ess_write (devc, 0xa2, div2); - } else { - ess_setmixer (devc, 0x70, div); - /* - * FKS: fascinating: 0x72 doesn't seem to work. - */ - ess_write (devc, 0xa2, div2); - ess_setmixer (devc, 0x72, div2); - } -} - -static int ess_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - ess_speed(devc, 1); - - sb_dsp_command(devc, DSP_CMD_SPKOFF); - - ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ - - ess_exec_commands (devc, ess_inp_cmds); - - ess_change (devc, 0xb1, 0xf0, 0x50); - ess_change (devc, 0xb2, 0xf0, 0x50); - - devc->trigger_bits = 0; - return 0; -} - -static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - - sb_dsp_reset(devc); - ess_speed(devc, 1); - ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ - ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ - - ess_exec_commands (devc, ess_out_cmds); - - ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable DMA */ - ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable IRQ */ - - sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */ - - devc->trigger_bits = 0; - return 0; -} - -static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - unsigned char bits; - -/* FKS: qqq - sb_dsp_reset(devc); -*/ - - /* - * Auto-Initialize: - * DMA mode + demand mode (8 bytes/request, yes I want it all!) - * But leave 16-bit DMA bit untouched! - */ - ess_chgmixer (devc, 0x78, 0xd0, 0xd0); - - ess_speed(devc, 2); - - /* bits 4:3 on ES1887 represent recording source. Keep them! */ - bits = ess_getmixer (devc, 0x7a) & 0x18; - - /* Set stereo/mono */ - if (devc->channels != 1) bits |= 0x02; - - /* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */ - if (devc->bits != AFMT_U8) bits |= 0x05; /* 16 bit */ - - /* Enable DMA, IRQ will be shared (hopefully)*/ - bits |= 0x60; - - ess_setmixer (devc, 0x7a, bits); - - ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */ - - devc->trigger_bits = 0; - return 0; -} - -static int ess_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - sb_devc *devc = audio_devs[dev]->devc; - -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "ess_audio_prepare_for_output: dma_out=%d,dma_in=%d\n" -, audio_devs[dev]->dmap_out->dma, audio_devs[dev]->dmap_in->dma); -#endif - - if (devc->duplex) { - return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount); - } else { - return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount); - } -} - -static void ess_audio_halt_xfer(int dev) -{ - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; - - spin_lock_irqsave(&devc->lock, flags); - sb_dsp_reset(devc); - spin_unlock_irqrestore(&devc->lock, flags); - - /* - * Audio 2 may still be operational! Creates awful sounds! - */ - if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00); -} - -static void ess_audio_start_input - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_change (devc, 0xb8, 0x0f, 0x0f); /* Go */ - devc->intr_active = 1; -} - -static void ess_audio_output_block_audio1 - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_change (devc, 0xb8, 0x05, 0x05); /* Go */ - devc->intr_active = 1; -} - -static void ess_audio_output_block_audio2 - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; - - if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; - count--; - - ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff)); - ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */ - - devc->irq_mode_16 = IMODE_OUTPUT; - devc->intr_active_16 = 1; -} - -static void ess_audio_output_block - (int dev, unsigned long buf, int nr_bytes, int intrflag) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (devc->duplex) { - ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag); - } else { - ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag); - } -} - -/* - * FKS: the if-statements for both bits and bits_16 are quite alike. - * Combine this... - */ -static void ess_audio_trigger(int dev, int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - int bits_16 = bits & devc->irq_mode_16; - bits &= devc->irq_mode; - - if (!bits && !bits_16) { - /* FKS oh oh.... wrong?? for dma 16? */ - sb_dsp_command(devc, 0xd0); /* Halt DMA */ - } - - if (bits) { - switch (devc->irq_mode) - { - case IMODE_INPUT: - ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } - - if (bits_16) { - switch (devc->irq_mode_16) { - case IMODE_INPUT: - ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - - case IMODE_OUTPUT: - ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16, - devc->trg_intrflag_16); - break; - } - } - - devc->trigger_bits = bits | bits_16; -} - -static int ess_audio_set_speed(int dev, int speed) -{ - sb_devc *devc = audio_devs[dev]->devc; - int minspeed, maxspeed, dummydiv; - - if (speed > 0) { - minspeed = (devc->duplex ? 6215 : 5000 ); - maxspeed = (devc->duplex ? 44100 : 48000); - if (speed < minspeed) speed = minspeed; - if (speed > maxspeed) speed = maxspeed; - - ess_common_speed (devc, &speed, &dummydiv); - - devc->speed = speed; - } - return devc->speed; -} - -/* - * FKS: This is a one-on-one copy of sb1_audio_set_bits - */ -static unsigned int ess_audio_set_bits(int dev, unsigned int bits) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (bits != 0) { - if (bits == AFMT_U8 || bits == AFMT_S16_LE) { - devc->bits = bits; - } else { - devc->bits = AFMT_U8; - } - } - - return devc->bits; -} - -/* - * FKS: This is a one-on-one copy of sbpro_audio_set_channels - * (*) Modified it!! - */ -static short ess_audio_set_channels(int dev, short channels) -{ - sb_devc *devc = audio_devs[dev]->devc; - - if (channels == 1 || channels == 2) devc->channels = channels; - - return devc->channels; -} - -static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ -{ - .owner = THIS_MODULE, - .open = sb_audio_open, - .close = sb_audio_close, - .output_block = ess_set_output_parms, - .start_input = ess_set_input_parms, - .prepare_for_input = ess_audio_prepare_for_input, - .prepare_for_output = ess_audio_prepare_for_output, - .halt_io = ess_audio_halt_xfer, - .trigger = ess_audio_trigger, - .set_speed = ess_audio_set_speed, - .set_bits = ess_audio_set_bits, - .set_channels = ess_audio_set_channels -}; - -/* - * ess_audio_init must be called from sb_audio_init - */ -struct audio_driver *ess_audio_init - (sb_devc *devc, int *audio_flags, int *format_mask) -{ - *audio_flags = DMA_AUTOMODE; - *format_mask |= AFMT_S16_LE; - - if (devc->duplex) { - int tmp_dma; - /* - * sb_audio_init thinks dma8 is for playback and - * dma16 is for record. Not now! So swap them. - */ - tmp_dma = devc->dma16; - devc->dma16 = devc->dma8; - devc->dma8 = tmp_dma; - - *audio_flags |= DMA_DUPLEX; - } - - return &ess_audio_driver; -} - -/**************************************************************************** - * * - * ESS common * - * * - ****************************************************************************/ -static void ess_handle_channel - (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode) -{ - if (!intr_active || !flag) return; -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode); -#endif - switch (irq_mode) { - case IMODE_OUTPUT: - DMAbuf_outputintr (dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr (dev); - break; - - case IMODE_INIT: - break; - - default:; - /* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */ - } -} - -/* - * FKS: TODO!!! Finish this! - * - * I think midi stuff uses uart401, without interrupts. - * So IMODE_MIDI isn't a value for devc->irq_mode. - */ -void ess_intr (sb_devc *devc) -{ - int status; - unsigned char src; - - if (devc->submodel == SUBMDL_ES1887) { - src = ess_getmixer (devc, 0x7f) >> 4; - } else { - src = 0xff; - } - -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src); -#endif - ess_handle_channel - ( "Audio 1" - , devc->dev, devc->intr_active , src & 0x01, devc->irq_mode ); - ess_handle_channel - ( "Audio 2" - , devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16); - /* - * Acknowledge interrupts - */ - if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) { - ess_chgmixer (devc, 0x7a, 0x80, 0x00); - } - - if (src & 0x01) { - status = inb(DSP_DATA_AVAIL); - } -} - -static void ess_extended (sb_devc * devc) -{ - /* Enable extended mode */ - - sb_dsp_command(devc, 0xc6); -} - -static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data) -{ -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: write reg %x: %x\n", reg, data); -#endif - /* Write a byte to an extended mode register of ES1688 */ - - if (!sb_dsp_command(devc, reg)) - return 0; - - return sb_dsp_command(devc, data); -} - -static int ess_read (sb_devc * devc, unsigned char reg) -{ - /* Read a byte from an extended mode register of ES1688 */ - - /* Read register command */ - if (!sb_dsp_command(devc, 0xc0)) return -1; - - if (!sb_dsp_command(devc, reg )) return -1; - - return sb_dsp_get_byte(devc); -} - -int ess_dsp_reset(sb_devc * devc) -{ - int loopc; - -#ifdef FKS_REG_LOGGING -printk(KERN_INFO "FKS: ess_dsp_reset 1\n"); -ess_show_mixerregs (devc); -#endif - - outb(3, DSP_RESET); /* Reset FIFO too */ - - udelay(10); - outb(0, DSP_RESET); - udelay(30); - - for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++); - - if (inb(DSP_READ) != 0xAA) { - DDB(printk("sb: No response to RESET\n")); - return 0; /* Sorry */ - } - ess_extended (devc); - -#ifdef FKS_LOGGING -printk(KERN_INFO "FKS: dsp_reset 2\n"); -ess_show_mixerregs (devc); -#endif - - return 1; -} - -static int ess_irq_bits (int irq) -{ - switch (irq) { - case 2: - case 9: - return 0; - - case 5: - return 1; - - case 7: - return 2; - - case 10: - return 3; - - default: - printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq); - return -1; - } -} - -/* - * Set IRQ configuration register for all ESS models - */ -static int ess_common_set_irq_hw (sb_devc * devc) -{ - int irq_bits; - - if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return 0; - - if (!ess_write (devc, 0xb1, 0x50 | (irq_bits << 2))) { - printk(KERN_ERR "ES1688: Failed to write to IRQ config register\n"); - return 0; - } - return 1; -} - -/* - * I wanna use modern ES1887 mixer irq handling. Funny is the - * fact that my BIOS wants the same. But suppose someone's BIOS - * doesn't do this! - * This is independent of duplex. If there's a 1887 this will - * prevent it from going into 1888 mode. - */ -static void ess_es1887_set_irq_hw (sb_devc * devc) -{ - int irq_bits; - - if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return; - - ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1)); -} - -static int ess_set_irq_hw (sb_devc * devc) -{ - if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc); - - return ess_common_set_irq_hw (devc); -} - -#ifdef FKS_TEST - -/* - * FKS_test: - * for ES1887: 00, 18, non wr bits: 0001 1000 - * for ES1868: 00, b8, non wr bits: 1011 1000 - * for ES1888: 00, f8, non wr bits: 1111 1000 - * for ES1688: 00, f8, non wr bits: 1111 1000 - * + ES968 - */ - -static void FKS_test (sb_devc * devc) -{ - int val1, val2; - val1 = ess_getmixer (devc, 0x64); - ess_setmixer (devc, 0x64, ~val1); - val2 = ess_getmixer (devc, 0x64) ^ ~val1; - ess_setmixer (devc, 0x64, val1); - val1 ^= ess_getmixer (devc, 0x64); -printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff)); -}; -#endif - -static unsigned int ess_identify (sb_devc * devc) -{ - unsigned int val; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - outb(((unsigned char) (0x40 & 0xff)), MIXER_ADDR); - - udelay(20); - val = inb(MIXER_DATA) << 8; - udelay(20); - val |= inb(MIXER_DATA); - udelay(20); - spin_unlock_irqrestore(&devc->lock, flags); - - return val; -} - -/* - * ESS technology describes a detection scheme in their docs. It involves - * fiddling with the bits in certain mixer registers. ess_probe is supposed - * to help. - * - * FKS: tracing shows ess_probe writes wrong value to 0x64. Bit 3 reads 1, but - * should be written 0 only. Check this. - */ -static int ess_probe (sb_devc * devc, int reg, int xorval) -{ - int val1, val2, val3; - - val1 = ess_getmixer (devc, reg); - val2 = val1 ^ xorval; - ess_setmixer (devc, reg, val2); - val3 = ess_getmixer (devc, reg); - ess_setmixer (devc, reg, val1); - - return (val2 == val3); -} - -int ess_init(sb_devc * devc, struct address_info *hw_config) -{ - unsigned char cfg; - int ess_major = 0, ess_minor = 0; - int i; - static char name[100], modelname[10]; - - /* - * Try to detect ESS chips. - */ - - sb_dsp_command(devc, 0xe7); /* Return identification */ - - for (i = 1000; i; i--) { - if (inb(DSP_DATA_AVAIL) & 0x80) { - if (ess_major == 0) { - ess_major = inb(DSP_READ); - } else { - ess_minor = inb(DSP_READ); - break; - } - } - } - - if (ess_major == 0) return 0; - - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) { - sprintf(name, "ESS ES488 AudioDrive (rev %d)", - ess_minor & 0x0f); - hw_config->name = name; - devc->model = MDL_SBPRO; - return 1; - } - - /* - * This the detection heuristic of ESS technology, though somewhat - * changed to actually make it work. - * This results in the following detection steps: - * - distinct between ES688 and ES1688+ (as always done in this driver) - * if ES688 we're ready - * - try to detect ES1868, ES1869 or ES1878 (ess_identify) - * if successful we're ready - * - try to detect ES1888, ES1887 or ES1788 (aim: detect ES1887) - * if successful we're ready - * - Dunno. Must be 1688. Will do in general - * - * This is the most BETA part of the software: Will the detection - * always work? - */ - devc->model = MDL_ESS; - devc->submodel = ess_minor & 0x0f; - - if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { - char *chip = NULL; - int submodel = -1; - - switch (devc->sbmo.esstype) { - case ESSTYPE_DETECT: - case ESSTYPE_LIKE20: - break; - case 688: - submodel = 0x00; - break; - case 1688: - submodel = 0x08; - break; - case 1868: - submodel = SUBMDL_ES1868; - break; - case 1869: - submodel = SUBMDL_ES1869; - break; - case 1788: - submodel = SUBMDL_ES1788; - break; - case 1878: - submodel = SUBMDL_ES1878; - break; - case 1879: - submodel = SUBMDL_ES1879; - break; - case 1887: - submodel = SUBMDL_ES1887; - break; - case 1888: - submodel = SUBMDL_ES1888; - break; - default: - printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype); - return 0; - } - if (submodel != -1) { - devc->submodel = submodel; - sprintf (modelname, "ES%d", devc->sbmo.esstype); - chip = modelname; - } - if (chip == NULL && (ess_minor & 0x0f) < 8) { - chip = "ES688"; - } -#ifdef FKS_TEST -FKS_test (devc); -#endif - /* - * If Nothing detected yet, and we want 2.0 behaviour... - * Then let's assume it's ES1688. - */ - if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) { - chip = "ES1688"; - } - - if (chip == NULL) { - int type; - - type = ess_identify (devc); - - switch (type) { - case 0x1868: - chip = "ES1868"; - devc->submodel = SUBMDL_ES1868; - break; - case 0x1869: - chip = "ES1869"; - devc->submodel = SUBMDL_ES1869; - break; - case 0x1878: - chip = "ES1878"; - devc->submodel = SUBMDL_ES1878; - break; - case 0x1879: - chip = "ES1879"; - devc->submodel = SUBMDL_ES1879; - break; - default: - if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { - printk ("ess_init: Unrecognized %04x\n", type); - } - } - } -#if 0 - /* - * this one failed: - * the probing of bit 4 is another thought: from ES1788 and up, all - * chips seem to have hardware volume control. Bit 4 is readonly to - * check if a hardware volume interrupt has fired. - * Cause ES688/ES1688 don't have this feature, bit 4 might be writeable - * for these chips. - */ - if (chip == NULL && !ess_probe(devc, 0x64, (1 << 4))) { -#endif - /* - * the probing of bit 2 is my idea. The ES1887 docs want me to probe - * bit 3. This results in ES1688 being detected as ES1788. - * Bit 2 is for "Enable HWV IRQE", but as ES(1)688 chips don't have - * HardWare Volume, I think they don't have this IRQE. - */ - if (chip == NULL && ess_probe(devc, 0x64, (1 << 2))) { - if (ess_probe (devc, 0x70, 0x7f)) { - if (ess_probe (devc, 0x64, (1 << 5))) { - chip = "ES1887"; - devc->submodel = SUBMDL_ES1887; - } else { - chip = "ES1888"; - devc->submodel = SUBMDL_ES1888; - } - } else { - chip = "ES1788"; - devc->submodel = SUBMDL_ES1788; - } - } - if (chip == NULL) { - chip = "ES1688"; - } - - printk(KERN_INFO "ESS chip %s %s%s\n", chip, - (devc->sbmo.esstype == ESSTYPE_DETECT || - devc->sbmo.esstype == ESSTYPE_LIKE20) ? - "detected" : "specified", - devc->sbmo.esstype == ESSTYPE_LIKE20 ? - " (kernel 2.0 compatible)" : ""); - - sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); - } else { - strcpy(name, "Jazz16"); - } - - /* AAS: info stolen from ALSA: these boards have different clocks */ - switch(devc->submodel) { -/* APPARENTLY NOT 1869 AND 1887 - case SUBMDL_ES1869: - case SUBMDL_ES1887: -*/ - case SUBMDL_ES1888: - devc->caps |= SB_CAP_ES18XX_RATE; - break; - } - - hw_config->name = name; - /* FKS: sb_dsp_reset to enable extended mode???? */ - sb_dsp_reset(devc); /* Turn on extended mode */ - - /* - * Enable joystick and OPL3 - */ - cfg = ess_getmixer (devc, 0x40); - ess_setmixer (devc, 0x40, cfg | 0x03); - if (devc->submodel >= 8) { /* ES1688 */ - devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ - } - sb_dsp_reset (devc); - - /* - * This is important! If it's not done, the IRQ probe in sb_dsp_init - * may fail. - */ - return ess_set_irq_hw (devc); -} - -static int ess_set_dma_hw(sb_devc * devc) -{ - unsigned char cfg, dma_bits = 0, dma16_bits; - int dma; - -#ifdef FKS_LOGGING -printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n" -, devc->dma8, devc->dma16, devc->duplex); -#endif - - /* - * FKS: It seems as if this duplex flag isn't set yet. Check it. - */ - dma = devc->dma8; - - if (dma > 3 || dma < 0 || dma == 2) { - dma_bits = 0; - printk(KERN_ERR "ESS1688: Invalid DMA8 %d\n", dma); - return 0; - } else { - /* Extended mode DMA enable */ - cfg = 0x50; - - if (dma == 3) { - dma_bits = 3; - } else { - dma_bits = dma + 1; - } - } - - if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) { - printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n"); - return 0; - } - - if (devc->duplex) { - dma = devc->dma16; - dma16_bits = 0; - - if (dma >= 0) { - switch (dma) { - case 0: - dma_bits = 0x04; - break; - case 1: - dma_bits = 0x05; - break; - case 3: - dma_bits = 0x06; - break; - case 5: - dma_bits = 0x07; - dma16_bits = 0x20; - break; - default: - printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma); - return 0; - } - ess_chgmixer (devc, 0x78, 0x20, dma16_bits); - ess_chgmixer (devc, 0x7d, 0x07, dma_bits); - } - } - return 1; -} - -/* - * This one is called from sb_dsp_init. - * - * Return values: - * 0: Failed - * 1: Succeeded or doesn't apply (not SUBMDL_ES1887) - */ -int ess_dsp_init (sb_devc *devc, struct address_info *hw_config) -{ - /* - * Caller also checks this, but anyway - */ - if (devc->model != MDL_ESS) { - printk (KERN_INFO "ess_dsp_init for non ESS chip\n"); - return 1; - } - /* - * This for ES1887 to run Full Duplex. Actually ES1888 - * is allowed to do so too. I have no idea yet if this - * will work for ES1888 however. - * - * For SB16 having both dma8 and dma16 means enable - * Full Duplex. Let's try this for ES1887 too - * - */ - if (devc->submodel == SUBMDL_ES1887) { - if (hw_config->dma2 != -1) { - devc->dma16 = hw_config->dma2; - } - /* - * devc->duplex initialization is put here, cause - * ess_set_dma_hw needs it. - */ - if (devc->dma8 != devc->dma16 && devc->dma16 != -1) { - devc->duplex = 1; - } - } - if (!ess_set_dma_hw (devc)) { - free_irq(devc->irq, devc); - return 0; - } - return 1; -} - -/**************************************************************************** - * * - * ESS mixer * - * * - ****************************************************************************/ - -#define ES688_RECORDING_DEVICES \ - ( SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD ) -#define ES688_MIXER_DEVICES \ - ( SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE \ - | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME \ - | SOUND_MASK_LINE2 | SOUND_MASK_SPEAKER ) - -#define ES1688_RECORDING_DEVICES \ - ( ES688_RECORDING_DEVICES ) -#define ES1688_MIXER_DEVICES \ - ( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV ) - -#define ES1887_RECORDING_DEVICES \ - ( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH) -#define ES1887_MIXER_DEVICES \ - ( ES1688_MIXER_DEVICES ) - -/* - * Mixer registers of ES1887 - * - * These registers specifically take care of recording levels. To make the - * mapping from playback devices to recording devices every recording - * devices = playback device + ES_REC_MIXER_RECDIFF - */ -#define ES_REC_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1) -#define ES_REC_MIXER_RECDIFF (ES_REC_MIXER_RECBASE - SOUND_MIXER_SYNTH) - -#define ES_REC_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECPCM (SOUND_MIXER_PCM + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE (SOUND_MIXER_LINE + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECMIC (SOUND_MIXER_MIC + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECCD (SOUND_MIXER_CD + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES_REC_MIXER_RECDIFF) -#define ES_REC_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES_REC_MIXER_RECDIFF) - -static mixer_tab es688_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -/* - * The ES1688 specifics... hopefully correct... - * - 6 bit master volume - * I was wrong, ES1888 docs say ES1688 didn't have it. - * - RECLEV control - * These may apply to ES688 too. I have no idea. - */ -static mixer_tab es1688_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -static mixer_tab es1688later_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -/* - * This one is for all ESS chips with a record mixer. - * It's not used (yet) however - */ -static mixer_tab es_rec_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4), -MIX_ENT(ES_REC_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(ES_REC_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4), -MIX_ENT(ES_REC_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4), -MIX_ENT(ES_REC_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4), -MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -/* - * This one is for ES1887. It's little different from es_rec_mix: it - * has 0x7c for PCM playback level. This is because ES1887 uses - * Audio 2 for playback. - */ -static mixer_tab es1887_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x7c, 7, 4, 0x7c, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), -MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), -MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4), -MIX_ENT(ES_REC_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECSPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(ES_REC_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4), -MIX_ENT(ES_REC_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4), -MIX_ENT(ES_REC_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4), -MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0) -}; - -static int ess_has_rec_mixer (int submodel) -{ - switch (submodel) { - case SUBMDL_ES1887: - return 1; - default: - return 0; - } -}; - -#ifdef FKS_LOGGING -static int ess_mixer_mon_regs[] - = { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f - , 0xa1, 0xa2, 0xa4, 0xa5, 0xa8, 0xa9 - , 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb9 - , 0x00}; - -static void ess_show_mixerregs (sb_devc *devc) -{ - int *mp = ess_mixer_mon_regs; - -return; - - while (*mp != 0) { - printk (KERN_INFO "res (%x)=%x\n", *mp, (int)(ess_getmixer (devc, *mp))); - mp++; - } -} -#endif - -void ess_setmixer (sb_devc * devc, unsigned int port, unsigned int value) -{ - unsigned long flags; - -#ifdef FKS_LOGGING -printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value); -#endif - - spin_lock_irqsave(&devc->lock, flags); - if (port >= 0xa0) { - ess_write (devc, port, value); - } else { - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - - udelay(20); - outb(((unsigned char) (value & 0xff)), MIXER_DATA); - udelay(20); - } - spin_unlock_irqrestore(&devc->lock, flags); -} - -unsigned int ess_getmixer (sb_devc * devc, unsigned int port) -{ - unsigned int val; - unsigned long flags; - - spin_lock_irqsave(&devc->lock, flags); - - if (port >= 0xa0) { - val = ess_read (devc, port); - } else { - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - - udelay(20); - val = inb(MIXER_DATA); - udelay(20); - } - spin_unlock_irqrestore(&devc->lock, flags); - - return val; -} - -static void ess_chgmixer - (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val) -{ - int value; - - value = ess_getmixer (devc, reg); - value = (value & ~mask) | (val & mask); - ess_setmixer (devc, reg, value); -} - -/* - * ess_mixer_init must be called from sb_mixer_init - */ -void ess_mixer_init (sb_devc * devc) -{ - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - - /* - * Take care of ES1887 specifics... - */ - switch (devc->submodel) { - case SUBMDL_ES1887: - devc->supported_devices = ES1887_MIXER_DEVICES; - devc->supported_rec_devices = ES1887_RECORDING_DEVICES; -#ifdef FKS_LOGGING -printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex); -#endif - if (devc->duplex) { - devc->iomap = &es1887_mix; - devc->iomap_sz = ARRAY_SIZE(es1887_mix); - } else { - devc->iomap = &es_rec_mix; - devc->iomap_sz = ARRAY_SIZE(es_rec_mix); - } - break; - default: - if (devc->submodel < 8) { - devc->supported_devices = ES688_MIXER_DEVICES; - devc->supported_rec_devices = ES688_RECORDING_DEVICES; - devc->iomap = &es688_mix; - devc->iomap_sz = ARRAY_SIZE(es688_mix); - } else { - /* - * es1688 has 4 bits master vol. - * later chips have 6 bits (?) - */ - devc->supported_devices = ES1688_MIXER_DEVICES; - devc->supported_rec_devices = ES1688_RECORDING_DEVICES; - if (devc->submodel < 0x10) { - devc->iomap = &es1688_mix; - devc->iomap_sz = ARRAY_SIZE(es688_mix); - } else { - devc->iomap = &es1688later_mix; - devc->iomap_sz = ARRAY_SIZE(es1688later_mix); - } - } - } -} - -/* - * Changing playback levels at an ESS chip with record mixer means having to - * take care of recording levels of recorded inputs (devc->recmask) too! - */ -int ess_mixer_set(sb_devc *devc, int dev, int left, int right) -{ - if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) { - sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right); - } - return sb_common_mixer_set (devc, dev, left, right); -} - -/* - * After a sb_dsp_reset extended register 0xb4 (RECLEV) is reset too. After - * sb_dsp_reset RECLEV has to be restored. This is where ess_mixer_reload - * helps. - */ -void ess_mixer_reload (sb_devc *devc, int dev) -{ - int left, right, value; - - value = devc->levels[dev]; - left = value & 0x000000ff; - right = (value & 0x0000ff00) >> 8; - - sb_common_mixer_set(devc, dev, left, right); -} - -static int es_rec_set_recmask(sb_devc * devc, int mask) -{ - int i, i_mask, cur_mask, diff_mask; - int value, left, right; - -#ifdef FKS_LOGGING -printk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask); -#endif - /* - * Changing the recmask on an ESS chip with recording mixer means: - * (1) Find the differences - * (2) For "turned-on" inputs: make the recording level the playback level - * (3) For "turned-off" inputs: make the recording level zero - */ - cur_mask = devc->recmask; - diff_mask = (cur_mask ^ mask); - - for (i = 0; i < 32; i++) { - i_mask = (1 << i); - if (diff_mask & i_mask) { /* Difference? (1) */ - if (mask & i_mask) { /* Turn it on (2) */ - value = devc->levels[i]; - left = value & 0x000000ff; - right = (value & 0x0000ff00) >> 8; - } else { /* Turn it off (3) */ - left = 0; - right = 0; - } - sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right); - } - } - return mask; -} - -int ess_set_recmask(sb_devc * devc, int *mask) -{ - /* This applies to ESS chips with record mixers only! */ - - if (ess_has_rec_mixer (devc->submodel)) { - *mask = es_rec_set_recmask (devc, *mask); - return 1; /* Applied */ - } else { - return 0; /* Not applied */ - } -} - -/* - * ess_mixer_reset must be called from sb_mixer_reset - */ -int ess_mixer_reset (sb_devc * devc) -{ - /* - * Separate actions for ESS chips with a record mixer: - */ - if (ess_has_rec_mixer (devc->submodel)) { - switch (devc->submodel) { - case SUBMDL_ES1887: - /* - * Separate actions for ES1887: - * Change registers 7a and 1c to make the record mixer the - * actual recording source. - */ - ess_chgmixer(devc, 0x7a, 0x18, 0x08); - ess_chgmixer(devc, 0x1c, 0x07, 0x07); - break; - } - /* - * Call set_recmask for proper initialization - */ - devc->recmask = devc->supported_rec_devices; - es_rec_set_recmask(devc, 0); - devc->recmask = 0; - - return 1; /* We took care of recmask. */ - } else { - return 0; /* We didn't take care; caller do it */ - } -} - -/**************************************************************************** - * * - * ESS midi * - * * - ****************************************************************************/ - -/* - * FKS: IRQ may be shared. Hm. And if so? Then What? - */ -int ess_midi_init(sb_devc * devc, struct address_info *hw_config) -{ - unsigned char cfg, tmp; - - cfg = ess_getmixer (devc, 0x40) & 0x03; - - if (devc->submodel < 8) { - ess_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ - return 0; /* ES688 doesn't support MPU401 mode */ - } - tmp = (hw_config->io_base & 0x0f0) >> 4; - - if (tmp > 3) { - ess_setmixer (devc, 0x40, cfg); - return 0; - } - cfg |= tmp << 3; - - tmp = 1; /* MPU enabled without interrupts */ - - /* May be shared: if so the value is -ve */ - - switch (abs(hw_config->irq)) { - case 9: - tmp = 0x4; - break; - case 5: - tmp = 0x5; - break; - case 7: - tmp = 0x6; - break; - case 10: - tmp = 0x7; - break; - default: - return 0; - } - - cfg |= tmp << 5; - ess_setmixer (devc, 0x40, cfg | 0x03); - - return 1; -} - diff --git a/sound/oss/sb_ess.h b/sound/oss/sb_ess.h deleted file mode 100644 index 1c741212bcfc..000000000000 --- a/sound/oss/sb_ess.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Created: 9-Jan-1999 Rolf Fokkens - */ - -extern void ess_intr - (sb_devc *devc); -extern int ess_dsp_init - (sb_devc *devc, struct address_info *hw_config); - -extern struct audio_driver *ess_audio_init - (sb_devc *devc, int *audio_flags, int *format_mask); -extern int ess_midi_init - (sb_devc *devc, struct address_info *hw_config); -extern void ess_mixer_init - (sb_devc *devc); - -extern int ess_init - (sb_devc *devc, struct address_info *hw_config); -extern int ess_dsp_reset - (sb_devc *devc); - -extern void ess_setmixer - (sb_devc *devc, unsigned int port, unsigned int value); -extern unsigned int ess_getmixer - (sb_devc *devc, unsigned int port); -extern int ess_mixer_set - (sb_devc *devc, int dev, int left, int right); -extern int ess_mixer_reset - (sb_devc *devc); -extern void ess_mixer_reload - (sb_devc * devc, int dev); -extern int ess_set_recmask - (sb_devc *devc, int *mask); - diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c deleted file mode 100644 index 551ee7557b4e..000000000000 --- a/sound/oss/sb_midi.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * sound/oss/sb_midi.c - * - * The low level driver for the Sound Blaster DS chips. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - -#include <linux/spinlock.h> -#include <linux/slab.h> - -#include "sound_config.h" - -#include "sb.h" -#undef SB_TEST_IRQ - -/* - * The DSP channel can be used either for input or output. Variable - * 'sb_irq_mode' will be set when the program calls read or write first time - * after open. Current version doesn't support mode changes without closing - * and reopening the device. Support for this feature may be implemented in a - * future version of this driver. - */ - - -static int sb_midi_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return -ENXIO; - - spin_lock_irqsave(&devc->lock, flags); - if (devc->opened) - { - spin_unlock_irqrestore(&devc->lock, flags); - return -EBUSY; - } - devc->opened = 1; - spin_unlock_irqrestore(&devc->lock, flags); - - devc->irq_mode = IMODE_MIDI; - devc->midi_broken = 0; - - sb_dsp_reset(devc); - - if (!sb_dsp_command(devc, 0x35)) /* Start MIDI UART mode */ - { - devc->opened = 0; - return -EIO; - } - devc->intr_active = 1; - - if (mode & OPEN_READ) - { - devc->input_opened = 1; - devc->midi_input_intr = input; - } - return 0; -} - -static void sb_midi_close(int dev) -{ - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return; - - spin_lock_irqsave(&devc->lock, flags); - sb_dsp_reset(devc); - devc->intr_active = 0; - devc->input_opened = 0; - devc->opened = 0; - spin_unlock_irqrestore(&devc->lock, flags); -} - -static int sb_midi_out(int dev, unsigned char midi_byte) -{ - sb_devc *devc = midi_devs[dev]->devc; - - if (devc == NULL) - return 1; - - if (devc->midi_broken) - return 1; - - if (!sb_dsp_command(devc, midi_byte)) - { - devc->midi_broken = 1; - return 1; - } - return 1; -} - -static int sb_midi_start_read(int dev) -{ - return 0; -} - -static int sb_midi_end_read(int dev) -{ - sb_devc *devc = midi_devs[dev]->devc; - - if (devc == NULL) - return -ENXIO; - - sb_dsp_reset(devc); - devc->intr_active = 0; - return 0; -} - -static int sb_midi_ioctl(int dev, unsigned cmd, void __user *arg) -{ - return -EINVAL; -} - -void sb_midi_interrupt(sb_devc * devc) -{ - unsigned long flags; - unsigned char data; - - if (devc == NULL) - return; - - spin_lock_irqsave(&devc->lock, flags); - - data = inb(DSP_READ); - if (devc->input_opened) - devc->midi_input_intr(devc->my_mididev, data); - - spin_unlock_irqrestore(&devc->lock, flags); -} - -#define MIDI_SYNTH_NAME "Sound Blaster Midi" -#define MIDI_SYNTH_CAPS 0 -#include "midi_synth.h" - -static struct midi_operations sb_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Sound Blaster", 0, 0, SNDCARD_SB}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = sb_midi_open, - .close = sb_midi_close, - .ioctl = sb_midi_ioctl, - .outputc = sb_midi_out, - .start_read = sb_midi_start_read, - .end_read = sb_midi_end_read, -}; - -void sb_dsp_midi_init(sb_devc * devc, struct module *owner) -{ - int dev; - - if (devc->model < 2) /* No MIDI support for SB 1.x */ - return; - - dev = sound_alloc_mididev(); - - if (dev == -1) - { - printk(KERN_ERR "sb_midi: too many MIDI devices detected\n"); - return; - } - std_midi_synth.midi_dev = devc->my_mididev = dev; - midi_devs[dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL); - if (midi_devs[dev] == NULL) - { - printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n"); - sound_unload_mididev(dev); - return; - } - memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, - sizeof(struct midi_operations)); - - if (owner) - midi_devs[dev]->owner = owner; - - midi_devs[dev]->devc = devc; - - - midi_devs[dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL); - if (midi_devs[dev]->converter == NULL) - { - printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n"); - kfree(midi_devs[dev]); - sound_unload_mididev(dev); - return; - } - memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth, - sizeof(struct synth_operations)); - - midi_devs[dev]->converter->id = "SBMIDI"; - sequencer_init(); -} diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c deleted file mode 100644 index acf7586aeb47..000000000000 --- a/sound/oss/sb_mixer.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * sound/oss/sb_mixer.c - * - * The low level mixer driver for the Sound Blaster compatible cards. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] - * Stanislav Voronyi <stas@esc.kharkov.com> : Support for AWE 3DSE device (Jun 7 1999) - */ - -#include <linux/slab.h> - -#include "sound_config.h" - -#define __SB_MIXER_C__ - -#include "sb.h" -#include "sb_mixer.h" - -#include "sb_ess.h" - -#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -/* Same as SB Pro, unless I find otherwise */ -#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES - -#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' - * channel is the COVOX/DisneySoundSource emulation volume control - * on the mixer. It does NOT control speaker volume. Should have own - * mask eventually? - */ -#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ - SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) - -#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ - SOUND_MASK_IMIX) - -/* These are the only devices that are working at the moment. Others could - * be added once they are identified and a method is found to control them. - */ -#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ - SOUND_MASK_PCM | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_VOLUME) - -static mixer_tab sbpro_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) -}; - -static mixer_tab sb16_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), -MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), -MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4), -MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5), -MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), -MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), -MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ -MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), -MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) -}; - -static mixer_tab als007_mix = -{ -MIX_ENT(SOUND_MIXER_VOLUME, 0x62, 7, 4, 0x62, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4), -MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4), -MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */ -MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) -}; - - -/* SM_GAMES Master volume is lower and PCM & FM volumes - higher than with SB Pro. This improves the - sound quality */ - -static int smg_default_levels[32] = -{ - 0x2020, /* Master Volume */ - 0x4b4b, /* Bass */ - 0x4b4b, /* Treble */ - 0x6464, /* FM */ - 0x6464, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x0000, /* Mic */ - 0x4b4b, /* CD */ - 0x4b4b, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ - 0x4b4b, /* Output gain */ - 0x4040, /* Line1 */ - 0x4040, /* Line2 */ - 0x1515 /* Line3 */ -}; - -static int sb_default_levels[32] = -{ - 0x5a5a, /* Master Volume */ - 0x4b4b, /* Bass */ - 0x4b4b, /* Treble */ - 0x4b4b, /* FM */ - 0x4b4b, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x1010, /* Mic */ - 0x4b4b, /* CD */ - 0x0000, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ - 0x4b4b, /* Output gain */ - 0x4040, /* Line1 */ - 0x4040, /* Line2 */ - 0x1515 /* Line3 */ -}; - -static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = -{ - 0x00, /* SOUND_MIXER_VOLUME */ - 0x00, /* SOUND_MIXER_BASS */ - 0x00, /* SOUND_MIXER_TREBLE */ - 0x40, /* SOUND_MIXER_SYNTH */ - 0x00, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x10, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x04, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00 /* SOUND_MIXER_OGAIN */ -}; - -static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = -{ - 0x00, /* SOUND_MIXER_VOLUME */ - 0x00, /* SOUND_MIXER_BASS */ - 0x00, /* SOUND_MIXER_TREBLE */ - 0x20, /* SOUND_MIXER_SYNTH */ - 0x00, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x08, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x02, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00 /* SOUND_MIXER_OGAIN */ -}; - -static char smw_mix_regs[] = /* Left mixer registers */ -{ - 0x0b, /* SOUND_MIXER_VOLUME */ - 0x0d, /* SOUND_MIXER_BASS */ - 0x0d, /* SOUND_MIXER_TREBLE */ - 0x05, /* SOUND_MIXER_SYNTH */ - 0x09, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x03, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x07, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00, /* SOUND_MIXER_OGAIN */ - 0x00, /* SOUND_MIXER_LINE1 */ - 0x00, /* SOUND_MIXER_LINE2 */ - 0x00 /* SOUND_MIXER_LINE3 */ -}; - -static int sbmixnum = 1; - -static void sb_mixer_reset(sb_devc * devc); - -void sb_mixer_set_stereo(sb_devc * devc, int mode) -{ - sb_chgmixer(devc, OUT_FILTER, STEREO_DAC, (mode ? STEREO_DAC : MONO_DAC)); -} - -static int detect_mixer(sb_devc * devc) -{ - /* Just trust the mixer is there */ - return 1; -} - -static void oss_change_bits(sb_devc *devc, unsigned char *regval, int dev, int chn, int newval) -{ - unsigned char mask; - int shift; - - mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* Scale */ - - shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; - - *regval &= ~(mask << shift); /* Mask out previous value */ - *regval |= (newval & mask) << shift; /* Set the new value */ -} - -static int sb_mixer_get(sb_devc * devc, int dev) -{ - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; - return devc->levels[dev]; -} - -void smw_mixer_init(sb_devc * devc) -{ - int i; - - sb_setmixer(devc, 0x00, 0x18); /* Mute unused (Telephone) line */ - sb_setmixer(devc, 0x10, 0x38); /* Config register 2 */ - - devc->supported_devices = 0; - for (i = 0; i < sizeof(smw_mix_regs); i++) - if (smw_mix_regs[i] != 0) - devc->supported_devices |= (1 << i); - - devc->supported_rec_devices = devc->supported_devices & - ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); - sb_mixer_reset(devc); -} - -int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right) -{ - int regoffs; - unsigned char val; - - if ((dev < 0) || (dev >= devc->iomap_sz)) - return -EINVAL; - - regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; - - if (regoffs == 0) - return -EINVAL; - - val = sb_getmixer(devc, regoffs); - oss_change_bits(devc, &val, dev, LEFT_CHN, left); - - if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* - * Change register - */ - { - sb_setmixer(devc, regoffs, val); /* - * Save the old one - */ - regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; - - if (regoffs == 0) - return left | (left << 8); /* - * Just left channel present - */ - - val = sb_getmixer(devc, regoffs); /* - * Read the new one - */ - } - oss_change_bits(devc, &val, dev, RIGHT_CHN, right); - - sb_setmixer(devc, regoffs, val); - - return left | (right << 8); -} - -static int smw_mixer_set(sb_devc * devc, int dev, int left, int right) -{ - int reg, val; - - switch (dev) - { - case SOUND_MIXER_VOLUME: - sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ - sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); - break; - - case SOUND_MIXER_BASS: - case SOUND_MIXER_TREBLE: - devc->levels[dev] = left | (right << 8); - /* Set left bass and treble values */ - val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; - val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer(devc, 0x0d, val); - - /* Set right bass and treble values */ - val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; - val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer(devc, 0x0e, val); - - break; - - default: - /* bounds check */ - if (dev < 0 || dev >= ARRAY_SIZE(smw_mix_regs)) - return -EINVAL; - reg = smw_mix_regs[dev]; - if (reg == 0) - return -EINVAL; - sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ - sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); - } - - devc->levels[dev] = left | (right << 8); - return left | (right << 8); -} - -static int sb_mixer_set(sb_devc * devc, int dev, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retval; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if ((dev < 0) || (dev > 31)) - return -EINVAL; - - if (!(devc->supported_devices & (1 << dev))) /* - * Not supported - */ - return -EINVAL; - - /* Differentiate depending on the chipsets */ - switch (devc->model) { - case MDL_SMW: - retval = smw_mixer_set(devc, dev, left, right); - break; - case MDL_ESS: - retval = ess_mixer_set(devc, dev, left, right); - break; - default: - retval = sb_common_mixer_set(devc, dev, left, right); - } - if (retval >= 0) devc->levels[dev] = retval; - - return retval; -} - -/* - * set_recsrc doesn't apply to ES188x - */ -static void set_recsrc(sb_devc * devc, int src) -{ - sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); -} - -static int set_recmask(sb_devc * devc, int mask) -{ - int devmask, i; - unsigned char regimageL, regimageR; - - devmask = mask & devc->supported_rec_devices; - - switch (devc->model) - { - case MDL_SBPRO: - case MDL_ESS: - case MDL_JAZZ: - case MDL_SMW: - if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) { - break; - } - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { - /* - * More than one device selected. Drop the - * previous selection - */ - devmask &= ~devc->recmask; - } - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { - /* - * More than one device selected. Default to - * mic - */ - devmask = SOUND_MASK_MIC; - } - if (devmask ^ devc->recmask) /* - * Input source changed - */ - { - switch (devmask) - { - case SOUND_MASK_MIC: - set_recsrc(devc, SRC__MIC); - break; - - case SOUND_MASK_LINE: - set_recsrc(devc, SRC__LINE); - break; - - case SOUND_MASK_CD: - set_recsrc(devc, SRC__CD); - break; - - default: - set_recsrc(devc, SRC__MIC); - } - } - break; - - case MDL_SB16: - if (!devmask) - devmask = SOUND_MASK_MIC; - - if (devc->submodel == SUBMDL_ALS007) - { - switch (devmask) - { - case SOUND_MASK_LINE: - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE); - break; - case SOUND_MASK_CD: - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD); - break; - case SOUND_MASK_SYNTH: - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH); - break; - default: /* Also takes care of SOUND_MASK_MIC case */ - sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC); - break; - } - } - else - { - regimageL = regimageR = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - { - if ((1 << i) & devmask) - { - regimageL |= sb16_recmasks_L[i]; - regimageR |= sb16_recmasks_R[i]; - } - sb_setmixer (devc, SB16_IMASK_L, regimageL); - sb_setmixer (devc, SB16_IMASK_R, regimageR); - } - } - break; - } - devc->recmask = devmask; - return devc->recmask; -} - -static int set_outmask(sb_devc * devc, int mask) -{ - int devmask, i; - unsigned char regimage; - - devmask = mask & devc->supported_out_devices; - - switch (devc->model) - { - case MDL_SB16: - if (devc->submodel == SUBMDL_ALS007) - break; - else - { - regimage = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - { - if ((1 << i) & devmask) - { - regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]); - } - sb_setmixer (devc, SB16_OMASK, regimage); - } - } - break; - default: - break; - } - - devc->outmask = devmask; - return devc->outmask; -} - -static int sb_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - sb_devc *devc = mixer_devs[dev]->devc; - int val, ret; - int __user *p = arg; - - /* - * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). - * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) - * or mode==2 put 3DSE state to mode. - */ - if (devc->model == MDL_SB16) { - if (cmd == SOUND_MIXER_AGC) - { - if (get_user(val, p)) - return -EFAULT; - sb_setmixer(devc, 0x43, (~val) & 0x01); - return 0; - } - if (cmd == SOUND_MIXER_3DSE) - { - /* I put here 15, but I don't know the exact version. - At least my 4.13 havn't 3DSE, 4.16 has it. */ - if (devc->minor < 15) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val == 0 || val == 1) - sb_chgmixer(devc, AWE_3DSE, 0x01, val); - else if (val == 2) - { - ret = sb_getmixer(devc, AWE_3DSE)&0x01; - return put_user(ret, p); - } - else - return -EINVAL; - return 0; - } - } - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - { - if (get_user(val, p)) - return -EFAULT; - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - ret = set_recmask(devc, val); - break; - - case SOUND_MIXER_OUTSRC: - ret = set_outmask(devc, val); - break; - - default: - ret = sb_mixer_set(devc, cmd & 0xff, val); - } - } - else switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - ret = devc->recmask; - break; - - case SOUND_MIXER_OUTSRC: - ret = devc->outmask; - break; - - case SOUND_MIXER_DEVMASK: - ret = devc->supported_devices; - break; - - case SOUND_MIXER_STEREODEVS: - ret = devc->supported_devices; - /* The ESS seems to have stereo mic controls */ - if (devc->model == MDL_ESS) - ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); - else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) - ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - break; - - case SOUND_MIXER_RECMASK: - ret = devc->supported_rec_devices; - break; - - case SOUND_MIXER_OUTMASK: - ret = devc->supported_out_devices; - break; - - case SOUND_MIXER_CAPS: - ret = devc->mixer_caps; - break; - - default: - ret = sb_mixer_get(devc, cmd & 0xff); - break; - } - return put_user(ret, p); - } else - return -EINVAL; -} - -static struct mixer_operations sb_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "SB", - .name = "Sound Blaster", - .ioctl = sb_mixer_ioctl -}; - -static struct mixer_operations als007_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "ALS007", - .name = "Avance ALS-007", - .ioctl = sb_mixer_ioctl -}; - -static void sb_mixer_reset(sb_devc * devc) -{ - char name[32]; - int i; - - sprintf(name, "SB_%d", devc->sbmixnum); - - if (devc->sbmo.sm_games) - devc->levels = load_mixer_volumes(name, smg_default_levels, 1); - else - devc->levels = load_mixer_volumes(name, sb_default_levels, 1); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - sb_mixer_set(devc, i, devc->levels[i]); - - if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) { - set_recmask(devc, SOUND_MASK_MIC); - } -} - -int sb_mixer_init(sb_devc * devc, struct module *owner) -{ - int mixer_type = 0; - int m; - - devc->sbmixnum = sbmixnum++; - devc->levels = NULL; - - sb_setmixer(devc, 0x00, 0); /* Reset mixer */ - - if (!(mixer_type = detect_mixer(devc))) - return 0; /* No mixer. Why? */ - - switch (devc->model) - { - case MDL_ESSPCI: - case MDL_YMPCI: - case MDL_SBPRO: - case MDL_AZTECH: - case MDL_JAZZ: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = SBPRO_MIXER_DEVICES; - devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; - devc->iomap = &sbpro_mix; - devc->iomap_sz = ARRAY_SIZE(sbpro_mix); - break; - - case MDL_ESS: - ess_mixer_init (devc); - break; - - case MDL_SMW: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = 0; - devc->supported_rec_devices = 0; - devc->iomap = &sbpro_mix; - devc->iomap_sz = ARRAY_SIZE(sbpro_mix); - smw_mixer_init(devc); - break; - - case MDL_SB16: - devc->mixer_caps = 0; - devc->supported_rec_devices = SB16_RECORDING_DEVICES; - devc->supported_out_devices = SB16_OUTFILTER_DEVICES; - if (devc->submodel != SUBMDL_ALS007) - { - devc->supported_devices = SB16_MIXER_DEVICES; - devc->iomap = &sb16_mix; - devc->iomap_sz = ARRAY_SIZE(sb16_mix); - } - else - { - devc->supported_devices = ALS007_MIXER_DEVICES; - devc->iomap = &als007_mix; - devc->iomap_sz = ARRAY_SIZE(als007_mix); - } - break; - - default: - printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model); - return 0; - } - - m = sound_alloc_mixerdev(); - if (m == -1) - return 0; - - mixer_devs[m] = kmalloc(sizeof(struct mixer_operations), GFP_KERNEL); - if (mixer_devs[m] == NULL) - { - printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); - sound_unload_mixerdev(m); - return 0; - } - - if (devc->submodel != SUBMDL_ALS007) - memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations)); - else - memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); - - mixer_devs[m]->devc = devc; - - if (owner) - mixer_devs[m]->owner = owner; - - devc->my_mixerdev = m; - sb_mixer_reset(devc); - return 1; -} - -void sb_mixer_unload(sb_devc *devc) -{ - if (devc->my_mixerdev == -1) - return; - - kfree(mixer_devs[devc->my_mixerdev]); - sound_unload_mixerdev(devc->my_mixerdev); - sbmixnum--; -} diff --git a/sound/oss/sb_mixer.h b/sound/oss/sb_mixer.h deleted file mode 100644 index 4b9425f085e3..000000000000 --- a/sound/oss/sb_mixer.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * sound/oss/sb_mixer.h - * - * Definitions for the SB Pro and SB16 mixers - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - -/* - * Modified: - * Hunyue Yau Jan 6 1994 - * Added defines for the Sound Galaxy NX Pro mixer. - * - * Rolf Fokkens Dec 20 1998 - * Added defines for some ES188x chips. - * - * Rolf Fokkens Dec 27 1998 - * Moved static stuff to sb_mixer.c - * - */ -/* - * Mixer registers - * - * NOTE! RECORD_SRC == IN_FILTER - */ - -/* - * Mixer registers of SB Pro - */ -#define VOC_VOL 0x04 -#define MIC_VOL 0x0A -#define MIC_MIX 0x0A -#define RECORD_SRC 0x0C -#define IN_FILTER 0x0C -#define OUT_FILTER 0x0E -#define MASTER_VOL 0x22 -#define FM_VOL 0x26 -#define CD_VOL 0x28 -#define LINE_VOL 0x2E -#define IRQ_NR 0x80 -#define DMA_NR 0x81 -#define IRQ_STAT 0x82 -#define OPSW 0x3c - -/* - * Additional registers on the SG NX Pro - */ -#define COVOX_VOL 0x42 -#define TREBLE_LVL 0x44 -#define BASS_LVL 0x46 - -#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */ -#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */ -#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */ -#define FILT_OFF (1 << 5) - -#define MONO_DAC 0x00 -#define STEREO_DAC 0x02 - -/* - * Mixer registers of SB16 - */ -#define SB16_OMASK 0x3c -#define SB16_IMASK_L 0x3d -#define SB16_IMASK_R 0x3e - -#define LEFT_CHN 0 -#define RIGHT_CHN 1 - -/* - * 3DSE register of AWE32/64 - */ -#define AWE_3DSE 0x90 - -/* - * Mixer registers of ALS007 - */ -#define ALS007_RECORD_SRC 0x6c -#define ALS007_OUTPUT_CTRL1 0x3c -#define ALS007_OUTPUT_CTRL2 0x4c - -#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ - {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} - -/* - * Recording sources (SB Pro) - */ - -#define SRC__MIC 1 /* Select Microphone recording source */ -#define SRC__CD 3 /* Select CD recording source */ -#define SRC__LINE 7 /* Use Line-in for recording source */ - -/* - * Recording sources for ALS-007 - */ - -#define ALS007_MIC 4 -#define ALS007_LINE 6 -#define ALS007_CD 2 -#define ALS007_SYNTH 7 diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c deleted file mode 100644 index f19da4b47c1d..000000000000 --- a/sound/oss/sequencer.c +++ /dev/null @@ -1,1661 +0,0 @@ -/* - * sound/oss/sequencer.c - * - * The sequencer personality manager. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Alan Cox : reformatted and fixed a pair of null pointer bugs - */ -#include <linux/kmod.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "midi_ctrl.h" -#include "sleep.h" - -static int sequencer_ok; -static struct sound_timer_operations *tmr; -static int tmr_no = -1; /* Currently selected timer */ -static int pending_timer = -1; /* For timer change operation */ -extern unsigned long seq_time; - -static int obsolete_api_used; -static DEFINE_SPINLOCK(lock); - -/* - * Local counts for number of synth and MIDI devices. These are initialized - * by the sequencer_open. - */ -static int max_mididev; -static int max_synthdev; - -/* - * The seq_mode gives the operating mode of the sequencer: - * 1 = level1 (the default) - * 2 = level2 (extended capabilities) - */ - -#define SEQ_1 1 -#define SEQ_2 2 -static int seq_mode = SEQ_1; - -static DECLARE_WAIT_QUEUE_HEAD(seq_sleeper); -static DECLARE_WAIT_QUEUE_HEAD(midi_sleeper); - -static int midi_opened[MAX_MIDI_DEV]; - -static int midi_written[MAX_MIDI_DEV]; - -static unsigned long prev_input_time; -static int prev_event_time; - -#include "tuning.h" - -#define EV_SZ 8 -#define IEV_SZ 8 - -static unsigned char *queue; -static unsigned char *iqueue; - -static volatile int qhead, qtail, qlen; -static volatile int iqhead, iqtail, iqlen; -static volatile int seq_playing; -static volatile int sequencer_busy; -static int output_threshold; -static long pre_event_timeout; -static unsigned synth_open_mask; - -static int seq_queue(unsigned char *note, char nonblock); -static void seq_startplay(void); -static int seq_sync(void); -static void seq_reset(void); - -#if MAX_SYNTH_DEV > 15 -#error Too many synthesizer devices enabled. -#endif - -int sequencer_read(int dev, struct file *file, char __user *buf, int count) -{ - int c = count, p = 0; - int ev_len; - unsigned long flags; - - dev = dev >> 4; - - ev_len = seq_mode == SEQ_1 ? 4 : 8; - - spin_lock_irqsave(&lock,flags); - - if (!iqlen) - { - spin_unlock_irqrestore(&lock,flags); - if (file->f_flags & O_NONBLOCK) { - return -EAGAIN; - } - - oss_broken_sleep_on(&midi_sleeper, pre_event_timeout); - spin_lock_irqsave(&lock,flags); - if (!iqlen) - { - spin_unlock_irqrestore(&lock,flags); - return 0; - } - } - while (iqlen && c >= ev_len) - { - char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; - spin_unlock_irqrestore(&lock,flags); - if (copy_to_user(&(buf)[p], fixit, ev_len)) - return count - c; - p += ev_len; - c -= ev_len; - - spin_lock_irqsave(&lock,flags); - iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; - iqlen--; - } - spin_unlock_irqrestore(&lock,flags); - return count - c; -} - -static void sequencer_midi_output(int dev) -{ - /* - * Currently NOP - */ -} - -void seq_copy_to_input(unsigned char *event_rec, int len) -{ - unsigned long flags; - - /* - * Verify that the len is valid for the current mode. - */ - - if (len != 4 && len != 8) - return; - if ((seq_mode == SEQ_1) != (len == 4)) - return; - - if (iqlen >= (SEQ_MAX_QUEUE - 1)) - return; /* Overflow */ - - spin_lock_irqsave(&lock,flags); - memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); - iqlen++; - iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - wake_up(&midi_sleeper); - spin_unlock_irqrestore(&lock,flags); -} -EXPORT_SYMBOL(seq_copy_to_input); - -static void sequencer_midi_input(int dev, unsigned char data) -{ - unsigned int tstamp; - unsigned char event_rec[4]; - - if (data == 0xfe) /* Ignore active sensing */ - return; - - tstamp = jiffies - seq_time; - - if (tstamp != prev_input_time) - { - tstamp = (tstamp << 8) | SEQ_WAIT; - seq_copy_to_input((unsigned char *) &tstamp, 4); - prev_input_time = tstamp; - } - event_rec[0] = SEQ_MIDIPUTC; - event_rec[1] = data; - event_rec[2] = dev; - event_rec[3] = 0; - - seq_copy_to_input(event_rec, 4); -} - -void seq_input_event(unsigned char *event_rec, int len) -{ - unsigned long this_time; - - if (seq_mode == SEQ_2) - this_time = tmr->get_time(tmr_no); - else - this_time = jiffies - seq_time; - - if (this_time != prev_input_time) - { - unsigned char tmp_event[8]; - - tmp_event[0] = EV_TIMING; - tmp_event[1] = TMR_WAIT_ABS; - tmp_event[2] = 0; - tmp_event[3] = 0; - *(unsigned int *) &tmp_event[4] = this_time; - - seq_copy_to_input(tmp_event, 8); - prev_input_time = this_time; - } - seq_copy_to_input(event_rec, len); -} -EXPORT_SYMBOL(seq_input_event); - -int sequencer_write(int dev, struct file *file, const char __user *buf, int count) -{ - unsigned char event_rec[EV_SZ], ev_code; - int p = 0, c, ev_size; - int mode = translate_mode(file); - - dev = dev >> 4; - - if (mode == OPEN_READ) - return -EIO; - - c = count; - - while (c >= 4) - { - if (copy_from_user((char *) event_rec, &(buf)[p], 4)) - goto out; - ev_code = event_rec[0]; - - if (ev_code == SEQ_FULLSIZE) - { - int err, fmt; - - dev = *(unsigned short *) &event_rec[2]; - if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) - return -ENXIO; - - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - - fmt = (*(short *) &event_rec[0]) & 0xffff; - err = synth_devs[dev]->load_patch(dev, fmt, buf + p, c, 0); - if (err < 0) - return err; - - return err; - } - if (ev_code >= 128) - { - if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) - { - printk(KERN_WARNING "Sequencer: Invalid level 2 event %x\n", ev_code); - return -EINVAL; - } - ev_size = 8; - - if (c < ev_size) - { - if (!seq_playing) - seq_startplay(); - return count - c; - } - if (copy_from_user((char *)&event_rec[4], - &(buf)[p + 4], 4)) - goto out; - - } - else - { - if (seq_mode == SEQ_2) - { - printk(KERN_WARNING "Sequencer: 4 byte event in level 2 mode\n"); - return -EINVAL; - } - ev_size = 4; - - if (event_rec[0] != SEQ_MIDIPUTC) - obsolete_api_used = 1; - } - - if (event_rec[0] == SEQ_MIDIPUTC) - { - if (!midi_opened[event_rec[2]]) - { - int err, mode; - int dev = event_rec[2]; - - if (dev >= max_mididev || midi_devs[dev]==NULL) - { - /*printk("Sequencer Error: Nonexistent MIDI device %d\n", dev);*/ - return -ENXIO; - } - mode = translate_mode(file); - - if ((err = midi_devs[dev]->open(dev, mode, - sequencer_midi_input, sequencer_midi_output)) < 0) - { - seq_reset(); - printk(KERN_WARNING "Sequencer Error: Unable to open Midi #%d\n", dev); - return err; - } - midi_opened[dev] = 1; - } - } - if (!seq_queue(event_rec, (file->f_flags & (O_NONBLOCK) ? 1 : 0))) - { - int processed = count - c; - - if (!seq_playing) - seq_startplay(); - - if (!processed && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; - else - return processed; - } - p += ev_size; - c -= ev_size; - } - - if (!seq_playing) - seq_startplay(); -out: - return count; -} - -static int seq_queue(unsigned char *note, char nonblock) -{ - - /* - * Test if there is space in the queue - */ - - if (qlen >= SEQ_MAX_QUEUE) - if (!seq_playing) - seq_startplay(); /* - * Give chance to drain the queue - */ - - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !waitqueue_active(&seq_sleeper)) { - /* - * Sleep until there is enough space on the queue - */ - oss_broken_sleep_on(&seq_sleeper, MAX_SCHEDULE_TIMEOUT); - } - if (qlen >= SEQ_MAX_QUEUE) - { - return 0; /* - * To be sure - */ - } - memcpy(&queue[qtail * EV_SZ], note, EV_SZ); - - qtail = (qtail + 1) % SEQ_MAX_QUEUE; - qlen++; - - return 1; -} - -static int extended_event(unsigned char *q) -{ - int dev = q[2]; - - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - - switch (q[1]) - { - case SEQ_NOTEOFF: - synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); - break; - - case SEQ_NOTEON: - if (q[4] > 127 && q[4] != 255) - return 0; - - if (q[5] == 0) - { - synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); - break; - } - synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); - break; - - case SEQ_PGMCHANGE: - synth_devs[dev]->set_instr(dev, q[3], q[4]); - break; - - case SEQ_AFTERTOUCH: - synth_devs[dev]->aftertouch(dev, q[3], q[4]); - break; - - case SEQ_BALANCE: - synth_devs[dev]->panning(dev, q[3], (char) q[4]); - break; - - case SEQ_CONTROLLER: - synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); - break; - - case SEQ_VOLMODE: - if (synth_devs[dev]->volume_method != NULL) - synth_devs[dev]->volume_method(dev, q[3]); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int find_voice(int dev, int chn, int note) -{ - unsigned short key; - int i; - - key = (chn << 8) | (note + 1); - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if (synth_devs[dev]->alloc.map[i] == key) - return i; - return -1; -} - -static int alloc_voice(int dev, int chn, int note) -{ - unsigned short key; - int voice; - - key = (chn << 8) | (note + 1); - - voice = synth_devs[dev]->alloc_voice(dev, chn, note, - &synth_devs[dev]->alloc); - synth_devs[dev]->alloc.map[voice] = key; - synth_devs[dev]->alloc.alloc_times[voice] = - synth_devs[dev]->alloc.timestamp++; - return voice; -} - -static void seq_chn_voice_event(unsigned char *event_rec) -{ -#define dev event_rec[1] -#define cmd event_rec[2] -#define chn event_rec[3] -#define note event_rec[4] -#define parm event_rec[5] - - int voice = -1; - - if ((int) dev > max_synthdev || synth_devs[dev] == NULL) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - if (seq_mode == SEQ_2) - { - if (synth_devs[dev]->alloc_voice) - voice = find_voice(dev, chn, note); - - if (cmd == MIDI_NOTEON && parm == 0) - { - cmd = MIDI_NOTEOFF; - parm = 64; - } - } - - switch (cmd) - { - case MIDI_NOTEON: - if (note > 127 && note != 255) /* Not a seq2 feature */ - return; - - if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) - { - /* Internal synthesizer (FM, GUS, etc) */ - voice = alloc_voice(dev, chn, note); - } - if (voice == -1) - voice = chn; - - if (seq_mode == SEQ_2 && (int) dev < num_synths) - { - /* - * The MIDI channel 10 is a percussive channel. Use the note - * number to select the proper patch (128 to 255) to play. - */ - - if (chn == 9) - { - synth_devs[dev]->set_instr(dev, voice, 128 + note); - synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; - } - synth_devs[dev]->setup_voice(dev, voice, chn); - } - synth_devs[dev]->start_note(dev, voice, note, parm); - break; - - case MIDI_NOTEOFF: - if (voice == -1) - voice = chn; - synth_devs[dev]->kill_note(dev, voice, note, parm); - break; - - case MIDI_KEY_PRESSURE: - if (voice == -1) - voice = chn; - synth_devs[dev]->aftertouch(dev, voice, parm); - break; - - default:; - } -#undef dev -#undef cmd -#undef chn -#undef note -#undef parm -} - - -static void seq_chn_common_event(unsigned char *event_rec) -{ - unsigned char dev = event_rec[1]; - unsigned char cmd = event_rec[2]; - unsigned char chn = event_rec[3]; - unsigned char p1 = event_rec[4]; - - /* unsigned char p2 = event_rec[5]; */ - unsigned short w14 = *(short *) &event_rec[6]; - - if ((int) dev > max_synthdev || synth_devs[dev] == NULL) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - switch (cmd) - { - case MIDI_PGM_CHANGE: - if (seq_mode == SEQ_2) - { - if (chn > 15) - break; - - synth_devs[dev]->chn_info[chn].pgm_num = p1; - if ((int) dev >= num_synths) - synth_devs[dev]->set_instr(dev, chn, p1); - } - else - synth_devs[dev]->set_instr(dev, chn, p1); - - break; - - case MIDI_CTL_CHANGE: - if (seq_mode == SEQ_2) - { - if (chn > 15 || p1 > 127) - break; - - synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; - - if (p1 < 32) /* Setting MSB should clear LSB to 0 */ - synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; - - if ((int) dev < num_synths) - { - int val = w14 & 0x7f; - int i, key; - - if (p1 < 64) /* Combine MSB and LSB */ - { - val = ((synth_devs[dev]-> - chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) - | (synth_devs[dev]-> - chn_info[chn].controllers[p1 | 32] & 0x7f); - p1 &= ~32; - } - /* Handle all playing notes on this channel */ - - key = ((int) chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->controller(dev, i, p1, val); - } - else - synth_devs[dev]->controller(dev, chn, p1, w14); - } - else /* Mode 1 */ - synth_devs[dev]->controller(dev, chn, p1, w14); - break; - - case MIDI_PITCH_BEND: - if (seq_mode == SEQ_2) - { - if (chn > 15) - break; - - synth_devs[dev]->chn_info[chn].bender_value = w14; - - if ((int) dev < num_synths) - { - /* Handle all playing notes on this channel */ - int i, key; - - key = (chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->bender(dev, i, w14); - } - else - synth_devs[dev]->bender(dev, chn, w14); - } - else /* MODE 1 */ - synth_devs[dev]->bender(dev, chn, w14); - break; - - default:; - } -} - -static int seq_timing_event(unsigned char *event_rec) -{ - unsigned char cmd = event_rec[1]; - unsigned int parm = *(int *) &event_rec[4]; - - if (seq_mode == SEQ_2) - { - int ret; - - if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - wake_up(&seq_sleeper); - return ret; - } - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - - /* - * NOTE! No break here. Execution of TMR_WAIT_REL continues in the - * next case (TMR_WAIT_ABS) - */ - - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - time = parm; - prev_event_time = time; - - seq_playing = 1; - request_sound_timer(time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - wake_up(&seq_sleeper); - return TIMER_ARMED; - } - break; - - case TMR_START: - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - break; - - case TMR_STOP: - break; - - case TMR_CONTINUE: - break; - - case TMR_TEMPO: - break; - - case TMR_ECHO: - parm = (parm << 8 | SEQ_ECHO); - seq_copy_to_input((unsigned char *) &parm, 4); - break; - - default:; - } - - return TIMER_NOT_ARMED; -} - -static void seq_local_event(unsigned char *event_rec) -{ - unsigned char cmd = event_rec[1]; - unsigned int parm = *((unsigned int *) &event_rec[4]); - - switch (cmd) - { - case LOCL_STARTAUDIO: - DMAbuf_start_devices(parm); - break; - - default:; - } -} - -static void seq_sysex_message(unsigned char *event_rec) -{ - unsigned int dev = event_rec[1]; - int i, l = 0; - unsigned char *buf = &event_rec[2]; - - if (dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - l = 0; - for (i = 0; i < 6 && buf[i] != 0xff; i++) - l = i + 1; - - if (!synth_devs[dev]->send_sysex) - return; - if (l > 0) - synth_devs[dev]->send_sysex(dev, buf, l); -} - -static int play_event(unsigned char *q) -{ - /* - * NOTE! This routine returns - * 0 = normal event played. - * 1 = Timer armed. Suspend playback until timer callback. - * 2 = MIDI output buffer full. Restore queue and suspend until timer - */ - unsigned int *delay; - - switch (q[0]) - { - case SEQ_NOTEOFF: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->kill_note(0, q[1], 255, q[3]); - break; - - case SEQ_NOTEON: - if (q[4] < 128 || q[4] == 255) - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->start_note(0, q[1], q[2], q[3]); - break; - - case SEQ_WAIT: - delay = (unsigned int *) q; /* - * Bytes 1 to 3 are containing the * - * delay in 'ticks' - */ - *delay = (*delay >> 8) & 0xffffff; - - if (*delay > 0) - { - long time; - - seq_playing = 1; - time = *delay; - prev_event_time = time; - - request_sound_timer(time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - wake_up(&seq_sleeper); - /* - * The timer is now active and will reinvoke this function - * after the timer expires. Return to the caller now. - */ - return 1; - } - break; - - case SEQ_PGMCHANGE: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->set_instr(0, q[1], q[2]); - break; - - case SEQ_SYNCTIMER: /* - * Reset timer - */ - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - break; - - case SEQ_MIDIPUTC: /* - * Put a midi character - */ - if (midi_opened[q[2]]) - { - int dev; - - dev = q[2]; - - if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - break; - - if (!midi_devs[dev]->outputc(dev, q[1])) - { - /* - * Output FIFO is full. Wait one timer cycle and try again. - */ - - seq_playing = 1; - request_sound_timer(-1); - return 2; - } - else - midi_written[dev] = 1; - } - break; - - case SEQ_ECHO: - seq_copy_to_input(q, 4); /* - * Echo back to the process - */ - break; - - case SEQ_PRIVATE: - if ((int) q[1] < max_synthdev) - synth_devs[q[1]]->hw_control(q[1], q); - break; - - case SEQ_EXTENDED: - extended_event(q); - break; - - case EV_CHN_VOICE: - seq_chn_voice_event(q); - break; - - case EV_CHN_COMMON: - seq_chn_common_event(q); - break; - - case EV_TIMING: - if (seq_timing_event(q) == TIMER_ARMED) - { - return 1; - } - break; - - case EV_SEQ_LOCAL: - seq_local_event(q); - break; - - case EV_SYSEX: - seq_sysex_message(q); - break; - - default:; - } - return 0; -} - -/* called also as timer in irq context */ -static void seq_startplay(void) -{ - int this_one, action; - unsigned long flags; - - while (qlen > 0) - { - - spin_lock_irqsave(&lock,flags); - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - spin_unlock_irqrestore(&lock,flags); - - seq_playing = 1; - - if ((action = play_event(&queue[this_one * EV_SZ]))) - { /* Suspend playback. Next timer routine invokes this routine again */ - if (action == 2) - { - qlen++; - qhead = this_one; - } - return; - } - } - - seq_playing = 0; - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - wake_up(&seq_sleeper); -} - -static void reset_controllers(int dev, unsigned char *controller, int update_dev) -{ - int i; - for (i = 0; i < 128; i++) - controller[i] = ctrl_def_values[i]; -} - -static void setup_mode2(void) -{ - int dev; - - max_synthdev = num_synths; - - for (dev = 0; dev < num_midis; dev++) - { - if (midi_devs[dev] && midi_devs[dev]->converter != NULL) - { - synth_devs[max_synthdev++] = midi_devs[dev]->converter; - } - } - - for (dev = 0; dev < max_synthdev; dev++) - { - int chn; - - synth_devs[dev]->sysex_ptr = 0; - synth_devs[dev]->emulation = 0; - - for (chn = 0; chn < 16; chn++) - { - synth_devs[dev]->chn_info[chn].pgm_num = 0; - reset_controllers(dev, - synth_devs[dev]->chn_info[chn].controllers,0); - synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ - synth_devs[dev]->chn_info[chn].bender_range = 200; - } - } - max_mididev = 0; - seq_mode = SEQ_2; -} - -int sequencer_open(int dev, struct file *file) -{ - int retval, mode, i; - int level, tmp; - - if (!sequencer_ok) - sequencer_init(); - - level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; - - dev = dev >> 4; - mode = translate_mode(file); - - if (!sequencer_ok) - { -/* printk("Sound card: sequencer not initialized\n");*/ - return -ENXIO; - } - if (dev) /* Patch manager device (obsolete) */ - return -ENXIO; - - if(synth_devs[dev] == NULL) - request_module("synth0"); - - if (mode == OPEN_READ) - { - if (!num_midis) - { - /*printk("Sequencer: No MIDI devices. Input not possible\n");*/ - sequencer_busy = 0; - return -ENXIO; - } - } - if (sequencer_busy) - { - return -EBUSY; - } - sequencer_busy = 1; - obsolete_api_used = 0; - - max_mididev = num_midis; - max_synthdev = num_synths; - pre_event_timeout = MAX_SCHEDULE_TIMEOUT; - seq_mode = SEQ_1; - - if (pending_timer != -1) - { - tmr_no = pending_timer; - pending_timer = -1; - } - if (tmr_no == -1) /* Not selected yet */ - { - int i, best; - - best = -1; - for (i = 0; i < num_sound_timers; i++) - if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) - { - tmr_no = i; - best = sound_timer_devs[i]->priority; - } - if (tmr_no == -1) /* Should not be */ - tmr_no = 0; - } - tmr = sound_timer_devs[tmr_no]; - - if (level == 2) - { - if (tmr == NULL) - { - /*printk("sequencer: No timer for level 2\n");*/ - sequencer_busy = 0; - return -ENXIO; - } - setup_mode2(); - } - if (!max_synthdev && !max_mididev) - { - sequencer_busy=0; - return -ENXIO; - } - - synth_open_mask = 0; - - for (i = 0; i < max_mididev; i++) - { - midi_opened[i] = 0; - midi_written[i] = 0; - } - - for (i = 0; i < max_synthdev; i++) - { - if (synth_devs[i]==NULL) - continue; - - if (!try_module_get(synth_devs[i]->owner)) - continue; - - if ((tmp = synth_devs[i]->open(i, mode)) < 0) - { - printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); - if (synth_devs[i]->midi_dev) - printk(KERN_WARNING "(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); - } - else - { - synth_open_mask |= (1 << i); - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 1; - } - } - - seq_time = jiffies; - - prev_input_time = 0; - prev_event_time = 0; - - if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) - { - /* - * Initialize midi input devices - */ - - for (i = 0; i < max_mididev; i++) - if (!midi_opened[i] && midi_devs[i]) - { - if (!try_module_get(midi_devs[i]->owner)) - continue; - - if ((retval = midi_devs[i]->open(i, mode, - sequencer_midi_input, sequencer_midi_output)) >= 0) - { - midi_opened[i] = 1; - } - } - } - - if (seq_mode == SEQ_2) { - if (try_module_get(tmr->owner)) - tmr->open(tmr_no, seq_mode); - } - - init_waitqueue_head(&seq_sleeper); - init_waitqueue_head(&midi_sleeper); - output_threshold = SEQ_MAX_QUEUE / 2; - - return 0; -} - -static void seq_drain_midi_queues(void) -{ - int i, n; - - /* - * Give the Midi drivers time to drain their output queues - */ - - n = 1; - - while (!signal_pending(current) && n) - { - n = 0; - - for (i = 0; i < max_mididev; i++) - if (midi_opened[i] && midi_written[i]) - if (midi_devs[i]->buffer_status != NULL) - if (midi_devs[i]->buffer_status(i)) - n++; - - /* - * Let's have a delay - */ - - if (n) - oss_broken_sleep_on(&seq_sleeper, HZ/10); - } -} - -void sequencer_release(int dev, struct file *file) -{ - int i; - int mode = translate_mode(file); - - dev = dev >> 4; - - /* - * Wait until the queue is empty (if we don't have nonblock) - */ - - if (mode != OPEN_READ && !(file->f_flags & O_NONBLOCK)) - { - while (!signal_pending(current) && qlen > 0) - { - seq_sync(); - oss_broken_sleep_on(&seq_sleeper, 3*HZ); - /* Extra delay */ - } - } - - if (mode != OPEN_READ) - seq_drain_midi_queues(); /* - * Ensure the output queues are empty - */ - seq_reset(); - if (mode != OPEN_READ) - seq_drain_midi_queues(); /* - * Flush the all notes off messages - */ - - for (i = 0; i < max_synthdev; i++) - { - if (synth_open_mask & (1 << i)) /* - * Actually opened - */ - if (synth_devs[i]) - { - synth_devs[i]->close(i); - - module_put(synth_devs[i]->owner); - - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 0; - } - } - - for (i = 0; i < max_mididev; i++) - { - if (midi_opened[i]) { - midi_devs[i]->close(i); - module_put(midi_devs[i]->owner); - } - } - - if (seq_mode == SEQ_2) { - tmr->close(tmr_no); - module_put(tmr->owner); - } - - if (obsolete_api_used) - printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm); - sequencer_busy = 0; -} - -static int seq_sync(void) -{ - if (qlen && !seq_playing && !signal_pending(current)) - seq_startplay(); - - if (qlen > 0) - oss_broken_sleep_on(&seq_sleeper, HZ); - return qlen; -} - -static void midi_outc(int dev, unsigned char data) -{ - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ - - int n; - unsigned long flags; - - /* - * This routine sends one byte to the Midi channel. - * If the output FIFO is full, it waits until there - * is space in the queue - */ - - n = 3 * HZ; /* Timeout */ - - spin_lock_irqsave(&lock,flags); - while (n && !midi_devs[dev]->outputc(dev, data)) { - oss_broken_sleep_on(&seq_sleeper, HZ/25); - n--; - } - spin_unlock_irqrestore(&lock,flags); -} - -static void seq_reset(void) -{ - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ - - int i; - int chn; - unsigned long flags; - - sound_stop_timer(); - - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - - qlen = qhead = qtail = 0; - iqlen = iqhead = iqtail = 0; - - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - synth_devs[i]->reset(i); - - if (seq_mode == SEQ_2) - { - for (chn = 0; chn < 16; chn++) - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - { - synth_devs[i]->controller(i, chn, 123, 0); /* All notes off */ - synth_devs[i]->controller(i, chn, 121, 0); /* Reset all ctl */ - synth_devs[i]->bender(i, chn, 1 << 13); /* Bender off */ - } - } - else /* seq_mode == SEQ_1 */ - { - for (i = 0; i < max_mididev; i++) - if (midi_written[i]) /* - * Midi used. Some notes may still be playing - */ - { - /* - * Sending just a ACTIVE SENSING message should be enough to stop all - * playing notes. Since there are devices not recognizing the - * active sensing, we have to send some all notes off messages also. - */ - midi_outc(i, 0xfe); - - for (chn = 0; chn < 16; chn++) - { - midi_outc(i, (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ - midi_outc(i, 0x7b); /* All notes off */ - midi_outc(i, 0); /* Dummy parameter */ - } - - midi_devs[i]->close(i); - - midi_written[i] = 0; - midi_opened[i] = 0; - } - } - - seq_playing = 0; - - spin_lock_irqsave(&lock,flags); - - if (waitqueue_active(&seq_sleeper)) { - /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ - wake_up(&seq_sleeper); - } - spin_unlock_irqrestore(&lock,flags); -} - -static void seq_panic(void) -{ - /* - * This routine is called by the application in case the user - * wants to reset the system to the default state. - */ - - seq_reset(); - - /* - * Since some of the devices don't recognize the active sensing and - * all notes off messages, we have to shut all notes manually. - * - * TO BE IMPLEMENTED LATER - */ - - /* - * Also return the controllers to their default states - */ -} - -int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) -{ - int midi_dev, orig_dev, val, err; - int mode = translate_mode(file); - struct synth_info inf; - struct seq_event_rec event_rec; - int __user *p = arg; - - orig_dev = dev = dev >> 4; - - switch (cmd) - { - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SOURCE: - if (seq_mode != SEQ_2) - return -EINVAL; - return tmr->ioctl(tmr_no, cmd, arg); - - case SNDCTL_TMR_SELECT: - if (seq_mode != SEQ_2) - return -EINVAL; - if (get_user(pending_timer, p)) - return -EFAULT; - if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) - { - pending_timer = -1; - return -EINVAL; - } - val = pending_timer; - break; - - case SNDCTL_SEQ_PANIC: - seq_panic(); - return -EINVAL; - - case SNDCTL_SEQ_SYNC: - if (mode == OPEN_READ) - return 0; - while (qlen > 0 && !signal_pending(current)) - seq_sync(); - return qlen ? -EINTR : 0; - - case SNDCTL_SEQ_RESET: - seq_reset(); - return 0; - - case SNDCTL_SEQ_TESTMIDI: - if (__get_user(midi_dev, p)) - return -EFAULT; - if (midi_dev < 0 || midi_dev >= max_mididev || !midi_devs[midi_dev]) - return -ENXIO; - - if (!midi_opened[midi_dev] && - (err = midi_devs[midi_dev]->open(midi_dev, mode, sequencer_midi_input, - sequencer_midi_output)) < 0) - return err; - midi_opened[midi_dev] = 1; - return 0; - - case SNDCTL_SEQ_GETINCOUNT: - if (mode == OPEN_WRITE) - return 0; - val = iqlen; - break; - - case SNDCTL_SEQ_GETOUTCOUNT: - if (mode == OPEN_READ) - return 0; - val = SEQ_MAX_QUEUE - qlen; - break; - - case SNDCTL_SEQ_GETTIME: - if (seq_mode == SEQ_2) - return tmr->ioctl(tmr_no, cmd, arg); - val = jiffies - seq_time; - break; - - case SNDCTL_SEQ_CTRLRATE: - /* - * If *arg == 0, just return the current rate - */ - if (seq_mode == SEQ_2) - return tmr->ioctl(tmr_no, cmd, arg); - - if (get_user(val, p)) - return -EFAULT; - if (val != 0) - return -EINVAL; - val = HZ; - break; - - case SNDCTL_SEQ_RESETSAMPLES: - case SNDCTL_SYNTH_REMOVESAMPLE: - case SNDCTL_SYNTH_CONTROL: - if (get_user(dev, p)) - return -EFAULT; - if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - return synth_devs[dev]->ioctl(dev, cmd, arg); - - case SNDCTL_SEQ_NRSYNTHS: - val = max_synthdev; - break; - - case SNDCTL_SEQ_NRMIDIS: - val = max_mididev; - break; - - case SNDCTL_SYNTH_MEMAVL: - if (get_user(dev, p)) - return -EFAULT; - if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - val = synth_devs[dev]->ioctl(dev, cmd, arg); - break; - - case SNDCTL_FM_4OP_ENABLE: - if (get_user(dev, p)) - return -EFAULT; - if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) - return -ENXIO; - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - synth_devs[dev]->ioctl(dev, cmd, arg); - return 0; - - case SNDCTL_SYNTH_INFO: - if (get_user(dev, &((struct synth_info __user *)arg)->device)) - return -EFAULT; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - return synth_devs[dev]->ioctl(dev, cmd, arg); - - /* Like SYNTH_INFO but returns ID in the name field */ - case SNDCTL_SYNTH_ID: - if (get_user(dev, &((struct synth_info __user *)arg)->device)) - return -EFAULT; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - memcpy(&inf, synth_devs[dev]->info, sizeof(inf)); - strlcpy(inf.name, synth_devs[dev]->id, sizeof(inf.name)); - inf.device = dev; - return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0; - - case SNDCTL_SEQ_OUTOFBAND: - if (copy_from_user(&event_rec, arg, sizeof(event_rec))) - return -EFAULT; - play_event(event_rec.arr); - return 0; - - case SNDCTL_MIDI_INFO: - if (get_user(dev, &((struct midi_info __user *)arg)->device)) - return -EFAULT; - if (dev < 0 || dev >= max_mididev || !midi_devs[dev]) - return -ENXIO; - midi_devs[dev]->info.device = dev; - return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; - - case SNDCTL_SEQ_THRESHOLD: - if (get_user(val, p)) - return -EFAULT; - if (val < 1) - val = 1; - if (val >= SEQ_MAX_QUEUE) - val = SEQ_MAX_QUEUE - 1; - output_threshold = val; - return 0; - - case SNDCTL_MIDI_PRETIME: - if (get_user(val, p)) - return -EFAULT; - if (val < 0) - val = 0; - val = (HZ * val) / 10; - pre_event_timeout = val; - break; - - default: - if (mode == OPEN_READ) - return -EIO; - if (!synth_devs[0]) - return -ENXIO; - if (!(synth_open_mask & (1 << 0))) - return -ENXIO; - if (!synth_devs[0]->ioctl) - return -EINVAL; - return synth_devs[0]->ioctl(0, cmd, arg); - } - return put_user(val, p); -} - -/* No kernel lock - we're using the global irq lock here */ -unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait) -{ - unsigned long flags; - unsigned int mask = 0; - - dev = dev >> 4; - - spin_lock_irqsave(&lock,flags); - /* input */ - poll_wait(file, &midi_sleeper, wait); - if (iqlen) - mask |= POLLIN | POLLRDNORM; - - /* output */ - poll_wait(file, &seq_sleeper, wait); - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - mask |= POLLOUT | POLLWRNORM; - spin_unlock_irqrestore(&lock,flags); - return mask; -} - - -void sequencer_timer(unsigned long dummy) -{ - seq_startplay(); -} -EXPORT_SYMBOL(sequencer_timer); - -int note_to_freq(int note_num) -{ - - /* - * This routine converts a midi note to a frequency (multiplied by 1000) - */ - - int note, octave, note_freq; - static int notes[] = - { - 261632, 277189, 293671, 311132, 329632, 349232, - 369998, 391998, 415306, 440000, 466162, 493880 - }; - -#define BASE_OCTAVE 5 - - octave = note_num / 12; - note = note_num % 12; - - note_freq = notes[note]; - - if (octave < BASE_OCTAVE) - note_freq >>= (BASE_OCTAVE - octave); - else if (octave > BASE_OCTAVE) - note_freq <<= (octave - BASE_OCTAVE); - - /* - * note_freq >>= 1; - */ - - return note_freq; -} -EXPORT_SYMBOL(note_to_freq); - -unsigned long compute_finetune(unsigned long base_freq, int bend, int range, - int vibrato_cents) -{ - unsigned long amount; - int negative, semitones, cents, multiplier = 1; - - if (!bend) - return base_freq; - if (!range) - return base_freq; - - if (!base_freq) - return base_freq; - - if (range >= 8192) - range = 8192; - - bend = bend * range / 8192; /* Convert to cents */ - bend += vibrato_cents; - - if (!bend) - return base_freq; - - negative = bend < 0 ? 1 : 0; - - if (bend < 0) - bend *= -1; - if (bend > range) - bend = range; - - /* - if (bend > 2399) - bend = 2399; - */ - while (bend > 2399) - { - multiplier *= 4; - bend -= 2400; - } - - semitones = bend / 100; - cents = bend % 100; - - amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000; - - if (negative) - return (base_freq * 10000) / amount; /* Bend down */ - else - return (base_freq * amount) / 10000; /* Bend up */ -} -EXPORT_SYMBOL(compute_finetune); - -void sequencer_init(void) -{ - if (sequencer_ok) - return; - queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ); - if (queue == NULL) - { - printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); - return; - } - iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ); - if (iqueue == NULL) - { - printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n"); - vfree(queue); - return; - } - sequencer_ok = 1; -} -EXPORT_SYMBOL(sequencer_init); - -void sequencer_unload(void) -{ - vfree(queue); - vfree(iqueue); - queue = iqueue = NULL; -} diff --git a/sound/oss/sleep.h b/sound/oss/sleep.h deleted file mode 100644 index fd17d44d13dd..000000000000 --- a/sound/oss/sleep.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include <linux/wait.h> - -/* - * Do not use. This is a replacement for the old - * "interruptible_sleep_on_timeout" function that has been - * deprecated for ages. All users should instead try to use - * wait_event_interruptible_timeout. - */ - -static inline long -oss_broken_sleep_on(wait_queue_head_t *q, long timeout) -{ - DEFINE_WAIT(wait); - prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE); - timeout = schedule_timeout(timeout); - finish_wait(q, &wait); - return timeout; -} diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h deleted file mode 100644 index bcd3f7340ef7..000000000000 --- a/sound/oss/sound_calls.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * DMA buffer calls - */ - -int DMAbuf_open(int dev, int mode); -int DMAbuf_release(int dev, int mode); -int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock); -int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock); -int DMAbuf_rmchars(int dev, int buff_no, int c); -int DMAbuf_start_output(int dev, int buff_no, int l); -int DMAbuf_move_wrpointer(int dev, int l); -/* int DMAbuf_ioctl(int dev, unsigned int cmd, void __user *arg, int local); */ -void DMAbuf_init(int dev, int dma1, int dma2); -void DMAbuf_deinit(int dev); -int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); -void DMAbuf_inputintr(int dev); -void DMAbuf_outputintr(int dev, int underflow_flag); -struct dma_buffparms; -int DMAbuf_space_in_queue (int dev); -int DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap); -int DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction); -void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap); -unsigned int DMAbuf_poll(struct file *file, int dev, poll_table *wait); -void DMAbuf_start_devices(unsigned int devmask); -void DMAbuf_reset (int dev); -int DMAbuf_sync (int dev); - -/* - * System calls for /dev/dsp and /dev/audio (audio.c) - */ - -int audio_read (int dev, struct file *file, char __user *buf, int count); -int audio_write (int dev, struct file *file, const char __user *buf, int count); -int audio_open (int dev, struct file *file); -void audio_release (int dev, struct file *file); -int audio_ioctl (int dev, struct file *file, - unsigned int cmd, void __user *arg); -void audio_init_devices (void); -void reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording); - -/* - * System calls for the /dev/sequencer - */ - -int sequencer_read (int dev, struct file *file, char __user *buf, int count); -int sequencer_write (int dev, struct file *file, const char __user *buf, int count); -int sequencer_open (int dev, struct file *file); -void sequencer_release (int dev, struct file *file); -int sequencer_ioctl (int dev, struct file *file, unsigned int cmd, void __user *arg); -unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait); - -void sequencer_init (void); -void sequencer_unload (void); -void sequencer_timer(unsigned long dummy); -int note_to_freq(int note_num); -unsigned long compute_finetune(unsigned long base_freq, int bend, int range, - int vibrato_bend); -void seq_input_event(unsigned char *event, int len); -void seq_copy_to_input (unsigned char *event, int len); - -/* - * System calls for the /dev/midi - */ - -int MIDIbuf_read (int dev, struct file *file, char __user *buf, int count); -int MIDIbuf_write (int dev, struct file *file, const char __user *buf, int count); -int MIDIbuf_open (int dev, struct file *file); -void MIDIbuf_release (int dev, struct file *file); -int MIDIbuf_ioctl (int dev, struct file *file, unsigned int cmd, void __user *arg); -unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait); -int MIDIbuf_avail(int dev); - -void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); - - -/* From soundcard.c */ -void request_sound_timer (int count); -void sound_stop_timer(void); -void conf_printf(char *name, struct address_info *hw_config); -void conf_printf2(char *name, int base, int irq, int dma, int dma2); - -/* From sound_timer.c */ -void sound_timer_interrupt(void); -void sound_timer_syncinterval(unsigned int new_usecs); - -/* From midi_synth.c */ -void do_midi_msg (int synthno, unsigned char *msg, int mlen); diff --git a/sound/oss/sound_config.h b/sound/oss/sound_config.h deleted file mode 100644 index 5253b0a70437..000000000000 --- a/sound/oss/sound_config.h +++ /dev/null @@ -1,144 +0,0 @@ -/* sound_config.h - * - * A driver for sound cards, misc. configuration parameters. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - - -#ifndef _SOUND_CONFIG_H_ -#define _SOUND_CONFIG_H_ - -#include <linux/fs.h> -#include <linux/sound.h> -#include <linux/sched/signal.h> - -#include "os.h" -#include "soundvers.h" - - -#ifndef SND_DEFAULT_ENABLE -#define SND_DEFAULT_ENABLE 1 -#endif - -#ifndef MAX_REALTIME_FACTOR -#define MAX_REALTIME_FACTOR 4 -#endif - -/* - * Use always 64k buffer size. There is no reason to use shorter. - */ -#undef DSP_BUFFSIZE -#define DSP_BUFFSIZE (64*1024) - -#ifndef DSP_BUFFCOUNT -#define DSP_BUFFCOUNT 1 /* 1 is recommended. */ -#endif - -#define FM_MONO 0x388 /* This is the I/O address used by AdLib */ - -#ifndef CONFIG_PAS_BASE -#define CONFIG_PAS_BASE 0x388 -#endif - -/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the - driver. (There is no need to alter this) */ -#define SEQ_MAX_QUEUE 1024 - -#define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */ -/* 128 instruments for general MIDI setup and 16 unassigned */ - -#define SND_NDEVS 256 /* Number of supported devices */ - -#define DSP_DEFAULT_SPEED 8000 - -#define MAX_AUDIO_DEV 5 -#define MAX_MIXER_DEV 5 -#define MAX_SYNTH_DEV 5 -#define MAX_MIDI_DEV 6 -#define MAX_TIMER_DEV 4 - -struct address_info { - int io_base; - int irq; - int dma; - int dma2; - int always_detect; /* 1=Trust me, it's there */ - char *name; - int driver_use_1; /* Driver defined field 1 */ - int driver_use_2; /* Driver defined field 2 */ - int *osp; /* OS specific info */ - int card_subtype; /* Driver specific. Usually 0 */ - void *memptr; /* Module memory chainer */ - int slots[6]; /* To remember driver slot ids */ -}; - -#define SYNTH_MAX_VOICES 32 - -struct voice_alloc_info { - int max_voice; - int used_voices; - int ptr; /* For device specific use */ - unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ - int timestamp; - int alloc_times[SYNTH_MAX_VOICES]; - }; - -struct channel_info { - int pgm_num; - int bender_value; - int bender_range; - unsigned char controllers[128]; - }; - -/* - * Process wakeup reasons - */ -#define WK_NONE 0x00 -#define WK_WAKEUP 0x01 -#define WK_TIMEOUT 0x02 -#define WK_SIGNAL 0x04 -#define WK_SLEEP 0x08 -#define WK_SELECT 0x10 -#define WK_ABORT 0x20 - -#define OPEN_READ PCM_ENABLE_INPUT -#define OPEN_WRITE PCM_ENABLE_OUTPUT -#define OPEN_READWRITE (OPEN_READ|OPEN_WRITE) - -static inline int translate_mode(struct file *file) -{ - if (OPEN_READ == (__force int)FMODE_READ && - OPEN_WRITE == (__force int)FMODE_WRITE) - return (__force int)(file->f_mode & (FMODE_READ | FMODE_WRITE)); - else - return ((file->f_mode & FMODE_READ) ? OPEN_READ : 0) | - ((file->f_mode & FMODE_WRITE) ? OPEN_WRITE : 0); -} - -#include "sound_calls.h" -#include "dev_table.h" - -#ifndef DDB -#define DDB(x) do {} while (0) -#endif - -#ifndef MDB -#ifdef MODULE -#define MDB(x) x -#else -#define MDB(x) -#endif -#endif - -#define TIMER_ARMED 121234 -#define TIMER_NOT_ARMED 1 - -#define MAX_MEM_BLOCKS 1024 - -#endif diff --git a/sound/oss/sound_firmware.h b/sound/oss/sound_firmware.h deleted file mode 100644 index ebcbded0e8c2..000000000000 --- a/sound/oss/sound_firmware.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include <linux/fs.h> - -/** - * mod_firmware_load - load sound driver firmware - * @fn: filename - * @fp: return for the buffer. - * - * Load the firmware for a sound module (up to 128K) into a buffer. - * The buffer is returned in *fp. It is allocated with vmalloc so is - * virtually linear and not DMAable. The caller should free it with - * vfree when finished. - * - * The length of the buffer is returned on a successful load, the - * value zero on a failure. - * - * Caution: This API is not recommended. Firmware should be loaded via - * request_firmware. - */ -static inline int mod_firmware_load(const char *fn, char **fp) -{ - loff_t size; - int err; - - err = kernel_read_file_from_path(fn, (void **)fp, &size, - 131072, READING_FIRMWARE); - if (err < 0) - return 0; - return size; -} diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c deleted file mode 100644 index 3a444a6f10eb..000000000000 --- a/sound/oss/sound_timer.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * sound/oss/sound_timer.c - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - */ -#include <linux/string.h> -#include <linux/spinlock.h> - -#include "sound_config.h" - -static volatile int initialized, opened, tmr_running; -static volatile unsigned int tmr_offs, tmr_ctr; -static volatile unsigned long ticks_offs; -static volatile int curr_tempo, curr_timebase; -static volatile unsigned long curr_ticks; -static volatile unsigned long next_event_time; -static unsigned long prev_event_time; -static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ - -static struct sound_lowlev_timer *tmr; -static DEFINE_SPINLOCK(lock); - -static unsigned long tmr2ticks(int tmr_value) -{ - /* - * Convert timer ticks to MIDI ticks - */ - - unsigned long tmp; - unsigned long scale; - - tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ - scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ - return (tmp + (scale / 2)) / scale; -} - -void reprogram_timer(void) -{ - unsigned long usecs_per_tick; - - /* - * The user is changing the timer rate before setting a timer - * slap, bad bad not allowed. - */ - - if(!tmr) - return; - - usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); - - /* - * Don't kill the system by setting too high timer rate - */ - if (usecs_per_tick < 2000) - usecs_per_tick = 2000; - - usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick); -} - -void sound_timer_syncinterval(unsigned int new_usecs) -{ - /* - * This routine is called by the hardware level if - * the clock frequency has changed for some reason. - */ - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks(tmr_ctr); - tmr_ctr = 0; - usecs_per_tmr = new_usecs; -} -EXPORT_SYMBOL(sound_timer_syncinterval); - -static void tmr_reset(void) -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - spin_unlock_irqrestore(&lock,flags); -} - -static int timer_open(int dev, int mode) -{ - if (opened) - return -EBUSY; - tmr_reset(); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - reprogram_timer(); - return 0; -} - -static void timer_close(int dev) -{ - opened = tmr_running = 0; - tmr->tmr_disable(tmr->dev); -} - -static int timer_event(int dev, unsigned char *event) -{ - unsigned char cmd = event[1]; - unsigned long parm = *(int *) &event[4]; - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - time = parm; - next_event_time = prev_event_time = time; - return TIMER_ARMED; - } - break; - - case TMR_START: - tmr_reset(); - tmr_running = 1; - reprogram_timer(); - break; - - case TMR_STOP: - tmr_running = 0; - break; - - case TMR_CONTINUE: - tmr_running = 1; - reprogram_timer(); - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks(tmr_ctr); - tmr_ctr = 0; - curr_tempo = parm; - reprogram_timer(); - } - break; - - case TMR_ECHO: - seq_copy_to_input(event, 8); - break; - - default:; - } - return TIMER_NOT_ARMED; -} - -static unsigned long timer_get_time(int dev) -{ - if (!opened) - return 0; - return curr_ticks; -} - -static int timer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int __user *p = arg; - int val; - - switch (cmd) - { - case SNDCTL_TMR_SOURCE: - val = TMR_INTERNAL; - break; - - case SNDCTL_TMR_START: - tmr_reset(); - tmr_running = 1; - return 0; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - - case SNDCTL_TMR_TIMEBASE: - if (get_user(val, p)) - return -EFAULT; - if (val) - { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - val = curr_timebase; - break; - - case SNDCTL_TMR_TEMPO: - if (get_user(val, p)) - return -EFAULT; - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks(tmr_ctr); - tmr_ctr = 0; - curr_tempo = val; - reprogram_timer(); - } - val = curr_tempo; - break; - - case SNDCTL_SEQ_CTRLRATE: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) /* Can't change */ - return -EINVAL; - val = ((curr_tempo * curr_timebase) + 30) / 60; - break; - - case SNDCTL_SEQ_GETTIME: - val = curr_ticks; - break; - - case SNDCTL_TMR_METRONOME: - default: - return -EINVAL; - } - return put_user(val, p); -} - -static void timer_arm(int dev, long time) -{ - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; - - next_event_time = prev_event_time = time; - return; -} - -static struct sound_timer_operations sound_timer = -{ - .owner = THIS_MODULE, - .info = {"Sound Timer", 0}, - .priority = 1, /* Priority */ - .devlink = 0, /* Local device link */ - .open = timer_open, - .close = timer_close, - .event = timer_event, - .get_time = timer_get_time, - .ioctl = timer_ioctl, - .arm_timer = timer_arm -}; - -void sound_timer_interrupt(void) -{ - unsigned long flags; - - if (!opened) - return; - - tmr->tmr_restart(tmr->dev); - - if (!tmr_running) - return; - - spin_lock_irqsave(&lock,flags); - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } - spin_unlock_irqrestore(&lock,flags); -} -EXPORT_SYMBOL(sound_timer_interrupt); - -void sound_timer_init(struct sound_lowlev_timer *t, char *name) -{ - int n; - - if (initialized) - { - if (t->priority <= tmr->priority) - return; /* There is already a similar or better timer */ - tmr = t; - return; - } - initialized = 1; - tmr = t; - - n = sound_alloc_timerdev(); - if (n == -1) - n = 0; /* Overwrite the system timer */ - strlcpy(sound_timer.info.name, name, sizeof(sound_timer.info.name)); - sound_timer_devs[n] = &sound_timer; -} -EXPORT_SYMBOL(sound_timer_init); - diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c deleted file mode 100644 index b70c7c8f9c5d..000000000000 --- a/sound/oss/soundcard.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * linux/sound/oss/soundcard.c - * - * Sound card driver for Linux - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * integrated sound_switch.c - * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, - * which should disappear in the near future) - * Eric Dumas : devfs support (22-Jan-98) <dumas@linux.eu.org> with - * fixups by C. Scott Ananian <cananian@alumni.princeton.edu> - * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c - * Rob Riggs : Added persistent DMA buffers support (1998/10/17) - * Christoph Hellwig : Some cleanup work (2000/03/01) - */ - - -#include "sound_config.h" -#include <linux/init.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/fcntl.h> -#include <linux/ctype.h> -#include <linux/stddef.h> -#include <linux/kmod.h> -#include <linux/kernel.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/wait.h> -#include <linux/ioport.h> -#include <linux/major.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/mutex.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/device.h> - -/* - * This ought to be moved into include/asm/dma.h - */ -#ifndef valid_dma -#define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4) -#endif - -/* - * Table for permanently allocated memory (used when unloading the module) - */ -void * sound_mem_blocks[MAX_MEM_BLOCKS]; -static DEFINE_MUTEX(soundcard_mutex); -int sound_nblocks = 0; - -/* Persistent DMA buffers */ -#ifdef CONFIG_SOUND_DMAP -int sound_dmap_flag = 1; -#else -int sound_dmap_flag = 0; -#endif - -static char dma_alloc_map[MAX_DMA_CHANNELS]; - -#define DMA_MAP_UNAVAIL 0 -#define DMA_MAP_FREE 1 -#define DMA_MAP_BUSY 2 - - -unsigned long seq_time = 0; /* Time for /dev/sequencer */ -extern struct class *sound_class; - -/* - * Table for configurable mixer volume handling - */ -static mixer_vol_table mixer_vols[MAX_MIXER_DEV]; -static int num_mixer_volumes; - -int *load_mixer_volumes(char *name, int *levels, int present) -{ - int i, n; - - for (i = 0; i < num_mixer_volumes; i++) { - if (strncmp(name, mixer_vols[i].name, 32) == 0) { - if (present) - mixer_vols[i].num = i; - return mixer_vols[i].levels; - } - } - if (num_mixer_volumes >= MAX_MIXER_DEV) { - printk(KERN_ERR "Sound: Too many mixers (%s)\n", name); - return levels; - } - n = num_mixer_volumes++; - - strncpy(mixer_vols[n].name, name, 32); - - if (present) - mixer_vols[n].num = n; - else - mixer_vols[n].num = -1; - - for (i = 0; i < 32; i++) - mixer_vols[n].levels[i] = levels[i]; - return mixer_vols[n].levels; -} -EXPORT_SYMBOL(load_mixer_volumes); - -static int set_mixer_levels(void __user * arg) -{ - /* mixer_vol_table is 174 bytes, so IMHO no reason to not allocate it on the stack */ - mixer_vol_table buf; - - if (__copy_from_user(&buf, arg, sizeof(buf))) - return -EFAULT; - load_mixer_volumes(buf.name, buf.levels, 0); - if (__copy_to_user(arg, &buf, sizeof(buf))) - return -EFAULT; - return 0; -} - -static int get_mixer_levels(void __user * arg) -{ - int n; - - if (__get_user(n, (int __user *)(&(((mixer_vol_table __user *)arg)->num)))) - return -EFAULT; - if (n < 0 || n >= num_mixer_volumes) - return -EINVAL; - if (__copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table))) - return -EFAULT; - return 0; -} - -/* 4K page size but our output routines use some slack for overruns */ -#define PROC_BLOCK_SIZE (3*1024) - -static ssize_t sound_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - int dev = iminor(file_inode(file)); - int ret = -EINVAL; - - /* - * The OSS drivers aren't remotely happy without this locking, - * and unless someone fixes them when they are about to bite the - * big one anyway, we might as well bandage here.. - */ - - mutex_lock(&soundcard_mutex); - - switch (dev & 0x0f) { - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = audio_read(dev, file, buf, count); - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - ret = sequencer_read(dev, file, buf, count); - break; - - case SND_DEV_MIDIN: - ret = MIDIbuf_read(dev, file, buf, count); - } - mutex_unlock(&soundcard_mutex); - return ret; -} - -static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - int dev = iminor(file_inode(file)); - int ret = -EINVAL; - - mutex_lock(&soundcard_mutex); - switch (dev & 0x0f) { - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - ret = sequencer_write(dev, file, buf, count); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = audio_write(dev, file, buf, count); - break; - - case SND_DEV_MIDIN: - ret = MIDIbuf_write(dev, file, buf, count); - break; - } - mutex_unlock(&soundcard_mutex); - return ret; -} - -static int sound_open(struct inode *inode, struct file *file) -{ - int dev = iminor(inode); - int retval; - - if ((dev >= SND_NDEVS) || (dev < 0)) { - printk(KERN_ERR "Invalid minor device %d\n", dev); - return -ENXIO; - } - mutex_lock(&soundcard_mutex); - switch (dev & 0x0f) { - case SND_DEV_CTL: - dev >>= 4; - if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { - request_module("mixer%d", dev); - } - retval = -ENXIO; - if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) - break; - - if (!try_module_get(mixer_devs[dev]->owner)) - break; - - retval = 0; - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - retval = sequencer_open(dev, file); - break; - - case SND_DEV_MIDIN: - retval = MIDIbuf_open(dev, file); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - retval = audio_open(dev, file); - break; - - default: - printk(KERN_ERR "Invalid minor device %d\n", dev); - retval = -ENXIO; - } - - mutex_unlock(&soundcard_mutex); - return retval; -} - -static int sound_release(struct inode *inode, struct file *file) -{ - int dev = iminor(inode); - - mutex_lock(&soundcard_mutex); - switch (dev & 0x0f) { - case SND_DEV_CTL: - module_put(mixer_devs[dev >> 4]->owner); - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - sequencer_release(dev, file); - break; - - case SND_DEV_MIDIN: - MIDIbuf_release(dev, file); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - audio_release(dev, file); - break; - - default: - printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); - } - mutex_unlock(&soundcard_mutex); - - return 0; -} - -static int get_mixer_info(int dev, void __user *arg) -{ - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); - strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); - info.modify_counter = mixer_devs[dev]->modify_counter; - if (__copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int get_old_mixer_info(int dev, void __user *arg) -{ - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); - strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) -{ - if (mixdev < 0 || mixdev >= MAX_MIXER_DEV) - return -ENXIO; - /* Try to load the mixer... */ - if (mixer_devs[mixdev] == NULL) { - request_module("mixer%d", mixdev); - } - if (mixdev >= num_mixers || !mixer_devs[mixdev]) - return -ENXIO; - if (cmd == SOUND_MIXER_INFO) - return get_mixer_info(mixdev, arg); - if (cmd == SOUND_OLD_MIXER_INFO) - return get_old_mixer_info(mixdev, arg); - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - mixer_devs[mixdev]->modify_counter++; - if (!mixer_devs[mixdev]->ioctl) - return -EINVAL; - return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); -} - -static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int len = 0, dtype; - int dev = iminor(file_inode(file)); - long ret = -EINVAL; - void __user *p = (void __user *)arg; - - if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { - /* - * Have to validate the address given by the process. - */ - len = _SIOC_SIZE(cmd); - if (len < 1 || len > 65536 || !p) - return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (!access_ok(VERIFY_READ, p, len)) - return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_READ) - if (!access_ok(VERIFY_WRITE, p, len)) - return -EFAULT; - } - if (cmd == OSS_GETVERSION) - return __put_user(SOUND_VERSION, (int __user *)p); - - mutex_lock(&soundcard_mutex); - if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ - (dev & 0x0f) != SND_DEV_CTL) { - dtype = dev & 0x0f; - switch (dtype) { - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, - cmd, p); - break; - default: - ret = sound_mixer_ioctl(dev >> 4, cmd, p); - break; - } - mutex_unlock(&soundcard_mutex); - return ret; - } - - switch (dev & 0x0f) { - case SND_DEV_CTL: - if (cmd == SOUND_MIXER_GETLEVELS) - ret = get_mixer_levels(p); - else if (cmd == SOUND_MIXER_SETLEVELS) - ret = set_mixer_levels(p); - else - ret = sound_mixer_ioctl(dev >> 4, cmd, p); - break; - - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - ret = sequencer_ioctl(dev, file, cmd, p); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - ret = audio_ioctl(dev, file, cmd, p); - break; - - case SND_DEV_MIDIN: - ret = MIDIbuf_ioctl(dev, file, cmd, p); - break; - - } - mutex_unlock(&soundcard_mutex); - return ret; -} - -static unsigned int sound_poll(struct file *file, poll_table * wait) -{ - struct inode *inode = file_inode(file); - int dev = iminor(inode); - - switch (dev & 0x0f) { - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_poll(dev, file, wait); - - case SND_DEV_MIDIN: - return MIDIbuf_poll(dev, file, wait); - - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return DMAbuf_poll(file, dev >> 4, wait); - } - return 0; -} - -static int sound_mmap(struct file *file, struct vm_area_struct *vma) -{ - int dev_class; - unsigned long size; - struct dma_buffparms *dmap = NULL; - int dev = iminor(file_inode(file)); - - dev_class = dev & 0x0f; - dev >>= 4; - - if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) { - printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); - return -EINVAL; - } - mutex_lock(&soundcard_mutex); - if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ - dmap = audio_devs[dev]->dmap_out; - else if (vma->vm_flags & VM_READ) - dmap = audio_devs[dev]->dmap_in; - else { - printk(KERN_ERR "Sound: Undefined mmap() access\n"); - mutex_unlock(&soundcard_mutex); - return -EINVAL; - } - - if (dmap == NULL) { - printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); - mutex_unlock(&soundcard_mutex); - return -EIO; - } - if (dmap->raw_buf == NULL) { - printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); - mutex_unlock(&soundcard_mutex); - return -EIO; - } - if (dmap->mapping_flags) { - printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); - mutex_unlock(&soundcard_mutex); - return -EIO; - } - if (vma->vm_pgoff != 0) { - printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); - mutex_unlock(&soundcard_mutex); - return -EINVAL; - } - size = vma->vm_end - vma->vm_start; - - if (size != dmap->bytes_in_use) { - printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); - } - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - mutex_unlock(&soundcard_mutex); - return -EAGAIN; - } - - dmap->mapping_flags |= DMA_MAP_MAPPED; - - if( audio_devs[dev]->d->mmap) - audio_devs[dev]->d->mmap(dev); - - memset(dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); - mutex_unlock(&soundcard_mutex); - return 0; -} - -const struct file_operations oss_sound_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = sound_read, - .write = sound_write, - .poll = sound_poll, - .unlocked_ioctl = sound_ioctl, - .mmap = sound_mmap, - .open = sound_open, - .release = sound_release, -}; - -/* - * Create the required special subdevices - */ - -static int create_special_devices(void) -{ - int seq1,seq2; - seq1=register_sound_special(&oss_sound_fops, 1); - if(seq1==-1) - goto bad; - seq2=register_sound_special(&oss_sound_fops, 8); - if(seq2!=-1) - return 0; - unregister_sound_special(1); -bad: - return -1; -} - - -static int dmabuf; -static int dmabug; - -module_param(dmabuf, int, 0444); -module_param(dmabug, int, 0444); - -/* additional minors for compatibility */ -struct oss_minor_dev { - unsigned short minor; - unsigned int enabled; -} dev_list[] = { - { SND_DEV_DSP16 }, - { SND_DEV_AUDIO }, -}; - -static int __init oss_init(void) -{ - int err; - int i, j; - -#ifdef CONFIG_PCI - if(dmabug) - isa_dma_bridge_buggy = dmabug; -#endif - - err = create_special_devices(); - if (err) { - printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); - return err; - } - - /* Protecting the innocent */ - sound_dmap_flag = (dmabuf > 0 ? 1 : 0); - - for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - j = 0; - do { - unsigned short minor = dev_list[i].minor + j * 0x10; - if (!register_sound_special(&oss_sound_fops, minor)) - dev_list[i].enabled = (1 << j); - } while (++j < num_audiodevs); - } - - if (sound_nblocks >= MAX_MEM_BLOCKS - 1) - printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); - - return 0; -} - -static void __exit oss_cleanup(void) -{ - int i, j; - - for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - j = 0; - do { - if (dev_list[i].enabled & (1 << j)) - unregister_sound_special(dev_list[i].minor); - } while (++j < num_audiodevs); - } - - unregister_sound_special(1); - unregister_sound_special(8); - - sound_stop_timer(); - - sequencer_unload(); - - for (i = 0; i < MAX_DMA_CHANNELS; i++) - if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) { - printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i); - sound_free_dma(i); - } - - for (i = 0; i < sound_nblocks; i++) - vfree(sound_mem_blocks[i]); - -} - -module_init(oss_init); -module_exit(oss_cleanup); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("OSS Sound subsystem"); -MODULE_AUTHOR("Hannu Savolainen, et al."); - - -int sound_alloc_dma(int chn, char *deviceID) -{ - int err; - - if ((err = request_dma(chn, deviceID)) != 0) - return err; - - dma_alloc_map[chn] = DMA_MAP_FREE; - - return 0; -} -EXPORT_SYMBOL(sound_alloc_dma); - -int sound_open_dma(int chn, char *deviceID) -{ - if (!valid_dma(chn)) { - printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); - return 1; - } - - if (dma_alloc_map[chn] != DMA_MAP_FREE) { - printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); - return 1; - } - dma_alloc_map[chn] = DMA_MAP_BUSY; - return 0; -} -EXPORT_SYMBOL(sound_open_dma); - -void sound_free_dma(int chn) -{ - if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) { - /* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */ - return; - } - free_dma(chn); - dma_alloc_map[chn] = DMA_MAP_UNAVAIL; -} -EXPORT_SYMBOL(sound_free_dma); - -void sound_close_dma(int chn) -{ - if (dma_alloc_map[chn] != DMA_MAP_BUSY) { - printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); - return; - } - dma_alloc_map[chn] = DMA_MAP_FREE; -} -EXPORT_SYMBOL(sound_close_dma); - -static void do_sequencer_timer(unsigned long dummy) -{ - sequencer_timer(0); -} - - -static DEFINE_TIMER(seq_timer, do_sequencer_timer, 0, 0); - -void request_sound_timer(int count) -{ - extern unsigned long seq_time; - - if (count < 0) { - seq_timer.expires = (-count) + jiffies; - add_timer(&seq_timer); - return; - } - count += seq_time; - - count -= jiffies; - - if (count < 1) - count = 1; - - seq_timer.expires = (count) + jiffies; - add_timer(&seq_timer); -} - -void sound_stop_timer(void) -{ - del_timer(&seq_timer); -} - -void conf_printf(char *name, struct address_info *hw_config) -{ -#ifndef CONFIG_SOUND_TRACEINIT - return; -#else - printk("<%s> at 0x%03x", name, hw_config->io_base); - - if (hw_config->irq) - printk(" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); - - if (hw_config->dma != -1 || hw_config->dma2 != -1) - { - printk(" dma %d", hw_config->dma); - if (hw_config->dma2 != -1) - printk(",%d", hw_config->dma2); - } - printk("\n"); -#endif -} -EXPORT_SYMBOL(conf_printf); - -void conf_printf2(char *name, int base, int irq, int dma, int dma2) -{ -#ifndef CONFIG_SOUND_TRACEINIT - return; -#else - printk("<%s> at 0x%03x", name, base); - - if (irq) - printk(" irq %d", (irq > 0) ? irq : -irq); - - if (dma != -1 || dma2 != -1) - { - printk(" dma %d", dma); - if (dma2 != -1) - printk(",%d", dma2); - } - printk("\n"); -#endif -} -EXPORT_SYMBOL(conf_printf2); - diff --git a/sound/oss/soundvers.h b/sound/oss/soundvers.h deleted file mode 100644 index e9084d2f46a9..000000000000 --- a/sound/oss/soundvers.h +++ /dev/null @@ -1,2 +0,0 @@ -#define SOUND_VERSION_STRING "3.8s2++-971130" -#define SOUND_INTERNAL_VERSION 0x030804 diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c deleted file mode 100644 index 97899352b15f..000000000000 --- a/sound/oss/swarm_cs4297a.c +++ /dev/null @@ -1,2781 +0,0 @@ -/******************************************************************************* -* -* "swarm_cs4297a.c" -- Cirrus Logic-Crystal CS4297a linux audio driver. -* -* Copyright (C) 2001 Broadcom Corporation. -* Copyright (C) 2000,2001 Cirrus Logic Corp. -* -- adapted from drivers by Thomas Sailer, -* -- but don't bug him; Problems should go to: -* -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). -* -- adapted from cs4281 PCI driver for cs4297a on -* BCM1250 Synchronous Serial interface -* (Kip Walker, Broadcom Corp.) -* Copyright (C) 2004 Maciej W. Rozycki -* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Module command line parameters: -* none -* -* Supported devices: -* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible -* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible -* /dev/midi simple MIDI UART interface, no ioctl -* -* Modification History -* 08/20/00 trw - silence and no stopping DAC until release -* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop. -* 09/18/00 trw - added 16bit only record with conversion -* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous -* capture/playback rates) -* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin -* libOSSm.so) -* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal) -* 11/03/00 trw - fixed interrupt loss/stutter, added debug. -* 11/10/00 bkz - added __devinit to cs4297a_hw_init() -* 11/10/00 trw - fixed SMP and capture spinlock hang. -* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm. -* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix. -* 12/08/00 trw - added PM support. -* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 -* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident. -* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup. -* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use -* defaultorder-100 as power of 2 for the buffer size. example: -* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. -* -*******************************************************************************/ - -#include <linux/list.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched/signal.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/pci.h> -#include <linux/bitops.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/mutex.h> -#include <linux/kernel.h> - -#include <asm/byteorder.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/uaccess.h> - -#include <asm/sibyte/sb1250_regs.h> -#include <asm/sibyte/sb1250_int.h> -#include <asm/sibyte/sb1250_dma.h> -#include <asm/sibyte/sb1250_scd.h> -#include <asm/sibyte/sb1250_syncser.h> -#include <asm/sibyte/sb1250_mac.h> -#include <asm/sibyte/sb1250.h> - -#include "sleep.h" - -struct cs4297a_state; - -static DEFINE_MUTEX(swarm_cs4297a_mutex); -static void stop_dac(struct cs4297a_state *s); -static void stop_adc(struct cs4297a_state *s); -static void start_dac(struct cs4297a_state *s); -static void start_adc(struct cs4297a_state *s); -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -// --------------------------------------------------------------------- - -#define CS4297a_MAGIC 0xf00beef1 - -// buffer order determines the size of the dma buffer for the driver. -// under Linux, a smaller buffer allows more responsiveness from many of the -// applications (e.g. games). A larger buffer allows some of the apps (esound) -// to not underrun the dma buffer as easily. As default, use 32k (order=3) -// rather than 64k as some of the games work more responsively. -// log base 2( buff sz = 32k). - -// -// Turn on/off debugging compilation by commenting out "#define CSDEBUG" -// -#define CSDEBUG 0 -#if CSDEBUG -#define CSDEBUG_INTERFACE 1 -#else -#undef CSDEBUG_INTERFACE -#endif -// -// cs_debugmask areas -// -#define CS_INIT 0x00000001 // initialization and probe functions -#define CS_ERROR 0x00000002 // tmp debugging bit placeholder -#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other) -#define CS_FUNCTION 0x00000008 // enter/leave functions -#define CS_WAVE_WRITE 0x00000010 // write information for wave -#define CS_WAVE_READ 0x00000020 // read information for wave -#define CS_AC97 0x00000040 // AC97 register access -#define CS_DESCR 0x00000080 // descriptor management -#define CS_OPEN 0x00000400 // all open functions in the driver -#define CS_RELEASE 0x00000800 // all release functions in the driver -#define CS_PARMS 0x00001000 // functional and operational parameters -#define CS_IOCTL 0x00002000 // ioctl (non-mixer) -#define CS_TMP 0x10000000 // tmp debug mask bit - -// -// CSDEBUG is usual mode is set to 1, then use the -// cs_debuglevel and cs_debugmask to turn on or off debugging. -// Debug level of 1 has been defined to be kernel errors and info -// that should be printed on any released driver. -// -#if CSDEBUG -#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;} -#else -#define CS_DBGOUT(mask,level,x) -#endif - -#if CSDEBUG -static unsigned long cs_debuglevel = 4; // levels range from 1-9 -static unsigned long cs_debugmask = CS_INIT /*| CS_IOCTL*/; -module_param(cs_debuglevel, int, 0); -module_param(cs_debugmask, int, 0); -#endif -#define CS_TRUE 1 -#define CS_FALSE 0 - -#define CS_TYPE_ADC 0 -#define CS_TYPE_DAC 1 - -#define SER_BASE (A_SER_BASE_1 + KSEG1) -#define SS_CSR(t) (SER_BASE+t) -#define SS_TXTBL(t) (SER_BASE+R_SER_TX_TABLE_BASE+(t*8)) -#define SS_RXTBL(t) (SER_BASE+R_SER_RX_TABLE_BASE+(t*8)) - -#define FRAME_BYTES 32 -#define FRAME_SAMPLE_BYTES 4 - -/* Should this be variable? */ -#define SAMPLE_BUF_SIZE (16*1024) -#define SAMPLE_FRAME_COUNT (SAMPLE_BUF_SIZE / FRAME_SAMPLE_BYTES) -/* The driver can explode/shrink the frames to/from a smaller sample - buffer */ -#define DMA_BLOAT_FACTOR 1 -#define DMA_DESCR (SAMPLE_FRAME_COUNT / DMA_BLOAT_FACTOR) -#define DMA_BUF_SIZE (DMA_DESCR * FRAME_BYTES) - -/* Use the maxmium count (255 == 5.1 ms between interrupts) */ -#define DMA_INT_CNT ((1 << S_DMA_INT_PKTCNT) - 1) - -/* Figure this out: how many TX DMAs ahead to schedule a reg access */ -#define REG_LATENCY 150 - -#define FRAME_TX_US 20 - -#define SERDMA_NEXTBUF(d,f) (((d)->f+1) % (d)->ringsz) - -static const char invalid_magic[] = - KERN_CRIT "cs4297a: invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != CS4297a_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* AC97 registers */ -#define AC97_MASTER_VOL_STEREO 0x0002 /* Line Out */ -#define AC97_PCBEEP_VOL 0x000a /* none */ -#define AC97_PHONE_VOL 0x000c /* TAD Input (mono) */ -#define AC97_MIC_VOL 0x000e /* MIC Input (mono) */ -#define AC97_LINEIN_VOL 0x0010 /* Line Input (stereo) */ -#define AC97_CD_VOL 0x0012 /* CD Input (stereo) */ -#define AC97_AUX_VOL 0x0016 /* Aux Input (stereo) */ -#define AC97_PCMOUT_VOL 0x0018 /* Wave Output (stereo) */ -#define AC97_RECORD_SELECT 0x001a /* */ -#define AC97_RECORD_GAIN 0x001c -#define AC97_GENERAL_PURPOSE 0x0020 -#define AC97_3D_CONTROL 0x0022 -#define AC97_POWER_CONTROL 0x0026 -#define AC97_VENDOR_ID1 0x007c - -struct list_head cs4297a_devs = { &cs4297a_devs, &cs4297a_devs }; - -typedef struct serdma_descr_s { - u64 descr_a; - u64 descr_b; -} serdma_descr_t; - -typedef unsigned long paddr_t; - -typedef struct serdma_s { - unsigned ringsz; - serdma_descr_t *descrtab; - serdma_descr_t *descrtab_end; - paddr_t descrtab_phys; - - serdma_descr_t *descr_add; - serdma_descr_t *descr_rem; - - u64 *dma_buf; // buffer for DMA contents (frames) - paddr_t dma_buf_phys; - u16 *sample_buf; // tmp buffer for sample conversions - u16 *sb_swptr; - u16 *sb_hwptr; - u16 *sb_end; - - dma_addr_t dmaaddr; -// unsigned buforder; // Log base 2 of 'dma_buf' size in bytes.. - unsigned numfrag; // # of 'fragments' in the buffer. - unsigned fragshift; // Log base 2 of fragment size. - unsigned hwptr, swptr; - unsigned total_bytes; // # bytes process since open. - unsigned blocks; // last returned blocks value GETOPTR - unsigned wakeup; // interrupt occurred on block - int count; - unsigned underrun; // underrun flag - unsigned error; // over/underrun - wait_queue_head_t wait; - wait_queue_head_t reg_wait; - // redundant, but makes calculations easier - unsigned fragsize; // 2**fragshift.. - unsigned sbufsz; // 2**buforder. - unsigned fragsamples; - // OSS stuff - unsigned mapped:1; // Buffer mapped in cs4297a_mmap()? - unsigned ready:1; // prog_dmabuf_dac()/adc() successful? - unsigned endcleared:1; - unsigned type:1; // adc or dac buffer (CS_TYPE_XXX) - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; -} serdma_t; - -struct cs4297a_state { - // magic - unsigned int magic; - - struct list_head list; - - // soundcore stuff - int dev_audio; - int dev_mixer; - - // hardware resources - unsigned int irq; - - struct { - unsigned int rx_ovrrn; /* FIFO */ - unsigned int rx_overflow; /* staging buffer */ - unsigned int tx_underrun; - unsigned int rx_bad; - unsigned int rx_good; - } stats; - - // mixer registers - struct { - unsigned short vol[10]; - unsigned int recsrc; - unsigned int modcnt; - unsigned short micpreamp; - } mix; - - // wave stuff - struct properties { - unsigned fmt; - unsigned fmt_original; // original requested format - unsigned channels; - unsigned rate; - } prop_dac, prop_adc; - unsigned conversion:1; // conversion from 16 to 8 bit in progress - unsigned ena; - spinlock_t lock; - struct mutex open_mutex; - struct mutex open_sem_adc; - struct mutex open_sem_dac; - fmode_t open_mode; - wait_queue_head_t open_wait; - wait_queue_head_t open_wait_adc; - wait_queue_head_t open_wait_dac; - - dma_addr_t dmaaddr_sample_buf; - unsigned buforder_sample_buf; // Log base 2 of 'dma_buf' size in bytes.. - - serdma_t dma_dac, dma_adc; - - volatile u16 read_value; - volatile u16 read_reg; - volatile u64 reg_request; -}; - -#if 1 -#define prog_codec(a,b) -#define dealloc_dmabuf(a,b); -#endif - -static int prog_dmabuf_adc(struct cs4297a_state *s) -{ - s->dma_adc.ready = 1; - return 0; -} - - -static int prog_dmabuf_dac(struct cs4297a_state *s) -{ - s->dma_dac.ready = 1; - return 0; -} - -static void clear_advance(void *buf, unsigned bsize, unsigned bptr, - unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *) buf) + bptr, c, x); - bptr = 0; - len -= x; - } - CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO - "cs4297a: clear_advance(): memset %d at 0x%.8x for %d size \n", - (unsigned)c, (unsigned)((char *) buf) + bptr, len)); - memset(((char *) buf) + bptr, c, len); -} - -#if CSDEBUG - -// DEBUG ROUTINES - -#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int) -#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) -#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) -#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) - -static void cs_printioctl(unsigned int x) -{ - unsigned int i; - unsigned char vidx; - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - switch (x) { - case SOUND_MIXER_CS_GETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_GETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_GETDBGLEVEL:\n")); - break; - case SOUND_MIXER_CS_SETDBGMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGMASK:\n")); - break; - case SOUND_MIXER_CS_SETDBGLEVEL: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_CS_SETDBGLEVEL:\n")); - break; - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n")); - break; - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n")); - break; - case SNDCTL_DSP_SETDUPLEX: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n")); - break; - case SNDCTL_DSP_GETCAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n")); - break; - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n")); - break; - case SNDCTL_DSP_SPEED: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n")); - break; - case SNDCTL_DSP_STEREO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n")); - break; - case SNDCTL_DSP_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n")); - break; - case SNDCTL_DSP_GETFMTS: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n")); - break; - case SNDCTL_DSP_SETFMT: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n")); - break; - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n")); - break; - case SNDCTL_DSP_GETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n")); - break; - case SNDCTL_DSP_SETTRIGGER: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n")); - break; - case SNDCTL_DSP_GETOSPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n")); - break; - case SNDCTL_DSP_GETISPACE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n")); - break; - case SNDCTL_DSP_NONBLOCK: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n")); - break; - case SNDCTL_DSP_GETODELAY: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n")); - break; - case SNDCTL_DSP_GETIPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n")); - break; - case SNDCTL_DSP_GETOPTR: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n")); - break; - case SNDCTL_DSP_GETBLKSIZE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n")); - break; - case SNDCTL_DSP_SETFRAGMENT: - CS_DBGOUT(CS_IOCTL, 4, - printk("SNDCTL_DSP_SETFRAGMENT:\n")); - break; - case SNDCTL_DSP_SUBDIVIDE: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n")); - break; - case SOUND_PCM_READ_RATE: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n")); - break; - case SOUND_PCM_READ_CHANNELS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_READ_CHANNELS:\n")); - break; - case SOUND_PCM_READ_BITS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n")); - break; - case SOUND_PCM_WRITE_FILTER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_PCM_WRITE_FILTER:\n")); - break; - case SNDCTL_DSP_SETSYNCRO: - CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n")); - break; - case SOUND_PCM_READ_FILTER: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n")); - break; - case SOUND_MIXER_PRIVATE1: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n")); - break; - case SOUND_MIXER_PRIVATE2: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n")); - break; - case SOUND_MIXER_PRIVATE3: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n")); - break; - case SOUND_MIXER_PRIVATE4: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n")); - break; - case SOUND_MIXER_PRIVATE5: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n")); - break; - case SOUND_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n")); - break; - case SOUND_OLD_MIXER_INFO: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n")); - break; - - default: - switch (_IOC_NR(x)) { - case SOUND_MIXER_VOLUME: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_VOLUME:\n")); - break; - case SOUND_MIXER_SPEAKER: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SPEAKER:\n")); - break; - case SOUND_MIXER_RECLEV: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECLEV:\n")); - break; - case SOUND_MIXER_MIC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_MIC:\n")); - break; - case SOUND_MIXER_SYNTH: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_SYNTH:\n")); - break; - case SOUND_MIXER_RECSRC: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECSRC:\n")); - break; - case SOUND_MIXER_DEVMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_DEVMASK:\n")); - break; - case SOUND_MIXER_RECMASK: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_RECMASK:\n")); - break; - case SOUND_MIXER_STEREODEVS: - CS_DBGOUT(CS_IOCTL, 4, - printk("SOUND_MIXER_STEREODEVS:\n")); - break; - case SOUND_MIXER_CAPS: - CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n")); - break; - default: - i = _IOC_NR(x); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) { - CS_DBGOUT(CS_IOCTL, 4, printk - ("UNKNOWN IOCTL: 0x%.8x NR=%d\n", - x, i)); - } else { - CS_DBGOUT(CS_IOCTL, 4, printk - ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n", - x, i)); - } - break; - } - } -} -#endif - - -static int ser_init(struct cs4297a_state *s) -{ - int i; - - CS_DBGOUT(CS_INIT, 2, - printk(KERN_INFO "cs4297a: Setting up serial parameters\n")); - - __raw_writeq(M_SYNCSER_CMD_RX_RESET | M_SYNCSER_CMD_TX_RESET, SS_CSR(R_SER_CMD)); - - __raw_writeq(M_SYNCSER_MSB_FIRST, SS_CSR(R_SER_MODE)); - __raw_writeq(32, SS_CSR(R_SER_MINFRM_SZ)); - __raw_writeq(32, SS_CSR(R_SER_MAXFRM_SZ)); - - __raw_writeq(1, SS_CSR(R_SER_TX_RD_THRSH)); - __raw_writeq(4, SS_CSR(R_SER_TX_WR_THRSH)); - __raw_writeq(8, SS_CSR(R_SER_RX_RD_THRSH)); - - /* This looks good from experimentation */ - __raw_writeq((M_SYNCSER_TXSYNC_INT | V_SYNCSER_TXSYNC_DLY(0) | M_SYNCSER_TXCLK_EXT | - M_SYNCSER_RXSYNC_INT | V_SYNCSER_RXSYNC_DLY(1) | M_SYNCSER_RXCLK_EXT | M_SYNCSER_RXSYNC_EDGE), - SS_CSR(R_SER_LINE_MODE)); - - /* This looks good from experimentation */ - __raw_writeq(V_SYNCSER_SEQ_COUNT(14) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE, - SS_TXTBL(0)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(15) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_TXTBL(1)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(13) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_TXTBL(2)); - __raw_writeq(V_SYNCSER_SEQ_COUNT( 0) | M_SYNCSER_SEQ_ENABLE | - M_SYNCSER_SEQ_STROBE | M_SYNCSER_SEQ_LAST, SS_TXTBL(3)); - - __raw_writeq(V_SYNCSER_SEQ_COUNT(14) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE, - SS_RXTBL(0)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(15) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_RXTBL(1)); - __raw_writeq(V_SYNCSER_SEQ_COUNT(13) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_BYTE, - SS_RXTBL(2)); - __raw_writeq(V_SYNCSER_SEQ_COUNT( 0) | M_SYNCSER_SEQ_ENABLE | M_SYNCSER_SEQ_STROBE | - M_SYNCSER_SEQ_LAST, SS_RXTBL(3)); - - for (i=4; i<16; i++) { - /* Just in case... */ - __raw_writeq(M_SYNCSER_SEQ_LAST, SS_TXTBL(i)); - __raw_writeq(M_SYNCSER_SEQ_LAST, SS_RXTBL(i)); - } - - return 0; -} - -static int init_serdma(serdma_t *dma) -{ - CS_DBGOUT(CS_INIT, 2, - printk(KERN_ERR "cs4297a: desc - %d sbufsize - %d dbufsize - %d\n", - DMA_DESCR, SAMPLE_BUF_SIZE, DMA_BUF_SIZE)); - - /* Descriptors */ - dma->ringsz = DMA_DESCR; - dma->descrtab = kzalloc(dma->ringsz * sizeof(serdma_descr_t), GFP_KERNEL); - if (!dma->descrtab) { - printk(KERN_ERR "cs4297a: kzalloc descrtab failed\n"); - return -1; - } - dma->descrtab_end = dma->descrtab + dma->ringsz; - /* XXX bloddy mess, use proper DMA API here ... */ - dma->descrtab_phys = CPHYSADDR((long)dma->descrtab); - dma->descr_add = dma->descr_rem = dma->descrtab; - - /* Frame buffer area */ - dma->dma_buf = kzalloc(DMA_BUF_SIZE, GFP_KERNEL); - if (!dma->dma_buf) { - printk(KERN_ERR "cs4297a: kzalloc dma_buf failed\n"); - kfree(dma->descrtab); - return -1; - } - dma->dma_buf_phys = CPHYSADDR((long)dma->dma_buf); - - /* Samples buffer area */ - dma->sbufsz = SAMPLE_BUF_SIZE; - dma->sample_buf = kmalloc(dma->sbufsz, GFP_KERNEL); - if (!dma->sample_buf) { - printk(KERN_ERR "cs4297a: kmalloc sample_buf failed\n"); - kfree(dma->descrtab); - kfree(dma->dma_buf); - return -1; - } - dma->sb_swptr = dma->sb_hwptr = dma->sample_buf; - dma->sb_end = (u16 *)((void *)dma->sample_buf + dma->sbufsz); - dma->fragsize = dma->sbufsz >> 1; - - CS_DBGOUT(CS_INIT, 4, - printk(KERN_ERR "cs4297a: descrtab - %08x dma_buf - %x sample_buf - %x\n", - (int)dma->descrtab, (int)dma->dma_buf, - (int)dma->sample_buf)); - - return 0; -} - -static int dma_init(struct cs4297a_state *s) -{ - int i; - - CS_DBGOUT(CS_INIT, 2, - printk(KERN_INFO "cs4297a: Setting up DMA\n")); - - if (init_serdma(&s->dma_adc) || - init_serdma(&s->dma_dac)) - return -1; - - if (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_RX))|| - __raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) { - panic("DMA state corrupted?!"); - } - - /* Initialize now - the descr/buffer pairings will never - change... */ - for (i=0; i<DMA_DESCR; i++) { - s->dma_dac.descrtab[i].descr_a = M_DMA_SERRX_SOP | V_DMA_DSCRA_A_SIZE(1) | - (s->dma_dac.dma_buf_phys + i*FRAME_BYTES); - s->dma_dac.descrtab[i].descr_b = V_DMA_DSCRB_PKT_SIZE(FRAME_BYTES); - s->dma_adc.descrtab[i].descr_a = V_DMA_DSCRA_A_SIZE(1) | - (s->dma_adc.dma_buf_phys + i*FRAME_BYTES); - s->dma_adc.descrtab[i].descr_b = 0; - } - - __raw_writeq((M_DMA_EOP_INT_EN | V_DMA_INT_PKTCNT(DMA_INT_CNT) | - V_DMA_RINGSZ(DMA_DESCR) | M_DMA_TDX_EN), - SS_CSR(R_SER_DMA_CONFIG0_RX)); - __raw_writeq(M_DMA_L2CA, SS_CSR(R_SER_DMA_CONFIG1_RX)); - __raw_writeq(s->dma_adc.descrtab_phys, SS_CSR(R_SER_DMA_DSCR_BASE_RX)); - - __raw_writeq(V_DMA_RINGSZ(DMA_DESCR), SS_CSR(R_SER_DMA_CONFIG0_TX)); - __raw_writeq(M_DMA_L2CA | M_DMA_NO_DSCR_UPDT, SS_CSR(R_SER_DMA_CONFIG1_TX)); - __raw_writeq(s->dma_dac.descrtab_phys, SS_CSR(R_SER_DMA_DSCR_BASE_TX)); - - /* Prep the receive DMA descriptor ring */ - __raw_writeq(DMA_DESCR, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - - __raw_writeq(M_SYNCSER_DMA_RX_EN | M_SYNCSER_DMA_TX_EN, SS_CSR(R_SER_DMA_ENABLE)); - - __raw_writeq((M_SYNCSER_RX_SYNC_ERR | M_SYNCSER_RX_OVERRUN | M_SYNCSER_RX_EOP_COUNT), - SS_CSR(R_SER_INT_MASK)); - - /* Enable the rx/tx; let the codec warm up to the sync and - start sending good frames before the receive FIFO is - enabled */ - __raw_writeq(M_SYNCSER_CMD_TX_EN, SS_CSR(R_SER_CMD)); - udelay(1000); - __raw_writeq(M_SYNCSER_CMD_RX_EN | M_SYNCSER_CMD_TX_EN, SS_CSR(R_SER_CMD)); - - /* XXXKW is this magic? (the "1" part) */ - while ((__raw_readq(SS_CSR(R_SER_STATUS)) & 0xf1) != 1) - ; - - CS_DBGOUT(CS_INIT, 4, - printk(KERN_INFO "cs4297a: status: %08x\n", - (unsigned int)(__raw_readq(SS_CSR(R_SER_STATUS)) & 0xffffffff))); - - return 0; -} - -static int serdma_reg_access(struct cs4297a_state *s, u64 data) -{ - serdma_t *d = &s->dma_dac; - u64 *data_p; - unsigned swptr; - unsigned long flags; - serdma_descr_t *descr; - - if (s->reg_request) { - printk(KERN_ERR "cs4297a: attempt to issue multiple reg_access\n"); - return -1; - } - - if (s->ena & FMODE_WRITE) { - /* Since a writer has the DSP open, we have to mux the - request in */ - s->reg_request = data; - oss_broken_sleep_on(&s->dma_dac.reg_wait, MAX_SCHEDULE_TIMEOUT); - /* XXXKW how can I deal with the starvation case where - the opener isn't writing? */ - } else { - /* Be safe when changing ring pointers */ - spin_lock_irqsave(&s->lock, flags); - if (d->hwptr != d->swptr) { - printk(KERN_ERR "cs4297a: reg access found bookkeeping error (hw/sw = %d/%d\n", - d->hwptr, d->swptr); - spin_unlock_irqrestore(&s->lock, flags); - return -1; - } - swptr = d->swptr; - d->hwptr = d->swptr = (d->swptr + 1) % d->ringsz; - spin_unlock_irqrestore(&s->lock, flags); - - descr = &d->descrtab[swptr]; - data_p = &d->dma_buf[swptr * 4]; - *data_p = cpu_to_be64(data); - __raw_writeq(1, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); - CS_DBGOUT(CS_DESCR, 4, - printk(KERN_INFO "cs4297a: add_tx %p (%x -> %x)\n", - data_p, swptr, d->hwptr)); - } - - CS_DBGOUT(CS_FUNCTION, 6, - printk(KERN_INFO "cs4297a: serdma_reg_access()-\n")); - - return 0; -} - -//**************************************************************************** -// "cs4297a_read_ac97" -- Reads an AC97 register -//**************************************************************************** -static int cs4297a_read_ac97(struct cs4297a_state *s, u32 offset, - u32 * value) -{ - CS_DBGOUT(CS_AC97, 1, - printk(KERN_INFO "cs4297a: read reg %2x\n", offset)); - if (serdma_reg_access(s, (0xCLL << 60) | (1LL << 47) | ((u64)(offset & 0x7F) << 40))) - return -1; - - oss_broken_sleep_on(&s->dma_adc.reg_wait, MAX_SCHEDULE_TIMEOUT); - *value = s->read_value; - CS_DBGOUT(CS_AC97, 2, - printk(KERN_INFO "cs4297a: rdr reg %x -> %x\n", s->read_reg, s->read_value)); - - return 0; -} - - -//**************************************************************************** -// "cs4297a_write_ac97()"-- writes an AC97 register -//**************************************************************************** -static int cs4297a_write_ac97(struct cs4297a_state *s, u32 offset, - u32 value) -{ - CS_DBGOUT(CS_AC97, 1, - printk(KERN_INFO "cs4297a: write reg %2x -> %04x\n", offset, value)); - return (serdma_reg_access(s, (0xELL << 60) | ((u64)(offset & 0x7F) << 40) | ((value & 0xffff) << 12))); -} - -static void stop_dac(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4297a: stop_dac():\n")); - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_WRITE; -#if 0 - /* XXXKW what do I really want here? My theory for now is - that I just flip the "ena" bit, and the interrupt handler - will stop processing the xmit channel */ - __raw_writeq((s->ena & FMODE_READ) ? M_SYNCSER_DMA_RX_EN : 0, - SS_CSR(R_SER_DMA_ENABLE)); -#endif - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void start_dac(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4297a: start_dac()+\n")); - spin_lock_irqsave(&s->lock, flags); - if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || - (s->dma_dac.count > 0 - && s->dma_dac.ready))) { - s->ena |= FMODE_WRITE; - /* XXXKW what do I really want here? My theory for - now is that I just flip the "ena" bit, and the - interrupt handler will start processing the xmit - channel */ - - CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO - "cs4297a: start_dac(): start dma\n")); - - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4297a: start_dac()-\n")); -} - - -static void stop_adc(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4297a: stop_adc()+\n")); - - spin_lock_irqsave(&s->lock, flags); - s->ena &= ~FMODE_READ; - - if (s->conversion == 1) { - s->conversion = 0; - s->prop_adc.fmt = s->prop_adc.fmt_original; - } - /* Nothing to do really, I need to keep the DMA going - XXXKW when do I get here, and is there more I should do? */ - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 3, - printk(KERN_INFO "cs4297a: stop_adc()-\n")); -} - - -static void start_adc(struct cs4297a_state *s) -{ - unsigned long flags; - - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: start_adc()+\n")); - - if (!(s->ena & FMODE_READ) && - (s->dma_adc.mapped || s->dma_adc.count <= - (signed) (s->dma_adc.sbufsz - 2 * s->dma_adc.fragsize)) - && s->dma_adc.ready) { - if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { - // - // now only use 16 bit capture, due to truncation issue - // in the chip, noticeable distortion occurs. - // allocate buffer and then convert from 16 bit to - // 8 bit for the user buffer. - // - s->prop_adc.fmt_original = s->prop_adc.fmt; - if (s->prop_adc.fmt & AFMT_S8) { - s->prop_adc.fmt &= ~AFMT_S8; - s->prop_adc.fmt |= AFMT_S16_LE; - } - if (s->prop_adc.fmt & AFMT_U8) { - s->prop_adc.fmt &= ~AFMT_U8; - s->prop_adc.fmt |= AFMT_U16_LE; - } - // - // prog_dmabuf_adc performs a stop_adc() but that is - // ok since we really haven't started the DMA yet. - // - prog_codec(s, CS_TYPE_ADC); - - prog_dmabuf_adc(s); - s->conversion = 1; - } - spin_lock_irqsave(&s->lock, flags); - s->ena |= FMODE_READ; - /* Nothing to do really, I am probably already - DMAing... XXXKW when do I get here, and is there - more I should do? */ - spin_unlock_irqrestore(&s->lock, flags); - - CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO - "cs4297a: start_adc(): start adc\n")); - } - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: start_adc()-\n")); - -} - - -// call with spinlock held! -static void cs4297a_update_ptr(struct cs4297a_state *s, int intflag) -{ - int good_diff, diff, diff2; - u64 *data_p, data; - u32 *s_ptr; - unsigned hwptr; - u32 status; - serdma_t *d; - serdma_descr_t *descr; - - // update ADC pointer - status = intflag ? __raw_readq(SS_CSR(R_SER_STATUS)) : 0; - - if ((s->ena & FMODE_READ) || (status & (M_SYNCSER_RX_EOP_COUNT))) { - d = &s->dma_adc; - hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - - d->descrtab_phys) / sizeof(serdma_descr_t)); - - if (s->ena & FMODE_READ) { - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: upd_rcv sw->hw->hw %x/%x/%x (int-%d)n", - d->swptr, d->hwptr, hwptr, intflag)); - /* Number of DMA buffers available for software: */ - diff2 = diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; - d->hwptr = hwptr; - good_diff = 0; - s_ptr = (u32 *)&(d->dma_buf[d->swptr*4]); - descr = &d->descrtab[d->swptr]; - while (diff2--) { - u64 data = be64_to_cpu(*(u64 *)s_ptr); - u64 descr_a; - u16 left, right; - descr_a = descr->descr_a; - descr->descr_a &= ~M_DMA_SERRX_SOP; - if ((descr_a & M_DMA_DSCRA_A_ADDR) != CPHYSADDR((long)s_ptr)) { - printk(KERN_ERR "cs4297a: RX Bad address (read)\n"); - } - if (((data & 0x9800000000000000) != 0x9800000000000000) || - (!(descr_a & M_DMA_SERRX_SOP)) || - (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { - s->stats.rx_bad++; - printk(KERN_DEBUG "cs4297a: RX Bad attributes (read)\n"); - continue; - } - s->stats.rx_good++; - if ((data >> 61) == 7) { - s->read_value = (data >> 12) & 0xffff; - s->read_reg = (data >> 40) & 0x7f; - wake_up(&d->reg_wait); - } - if (d->count && (d->sb_hwptr == d->sb_swptr)) { - s->stats.rx_overflow++; - printk(KERN_DEBUG "cs4297a: RX overflow\n"); - continue; - } - good_diff++; - left = ((be32_to_cpu(s_ptr[1]) & 0xff) << 8) | - ((be32_to_cpu(s_ptr[2]) >> 24) & 0xff); - right = (be32_to_cpu(s_ptr[2]) >> 4) & 0xffff; - *d->sb_hwptr++ = cpu_to_be16(left); - *d->sb_hwptr++ = cpu_to_be16(right); - if (d->sb_hwptr == d->sb_end) - d->sb_hwptr = d->sample_buf; - descr++; - if (descr == d->descrtab_end) { - descr = d->descrtab; - s_ptr = (u32 *)s->dma_adc.dma_buf; - } else { - s_ptr += 8; - } - } - d->total_bytes += good_diff * FRAME_SAMPLE_BYTES; - d->count += good_diff * FRAME_SAMPLE_BYTES; - if (d->count > d->sbufsz) { - printk(KERN_ERR "cs4297a: bogus receive overflow!!\n"); - } - d->swptr = (d->swptr + diff) % d->ringsz; - __raw_writeq(diff, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - if (d->mapped) { - if (d->count >= (signed) d->fragsize) - wake_up(&d->wait); - } else { - if (d->count > 0) { - CS_DBGOUT(CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4297a: update count -> %d\n", d->count)); - wake_up(&d->wait); - } - } - } else { - /* Receive is going even if no one is - listening (for register accesses and to - avoid FIFO overrun) */ - diff2 = diff = (hwptr + d->ringsz - d->hwptr) % d->ringsz; - if (!diff) { - printk(KERN_ERR "cs4297a: RX full or empty?\n"); - } - - descr = &d->descrtab[d->swptr]; - data_p = &d->dma_buf[d->swptr*4]; - - /* Force this to happen at least once; I got - here because of an interrupt, so there must - be a buffer to process. */ - do { - data = be64_to_cpu(*data_p); - if ((descr->descr_a & M_DMA_DSCRA_A_ADDR) != CPHYSADDR((long)data_p)) { - printk(KERN_ERR "cs4297a: RX Bad address %d (%llx %lx)\n", d->swptr, - (long long)(descr->descr_a & M_DMA_DSCRA_A_ADDR), - (long)CPHYSADDR((long)data_p)); - } - if (!(data & (1LL << 63)) || - !(descr->descr_a & M_DMA_SERRX_SOP) || - (G_DMA_DSCRB_PKT_SIZE(descr->descr_b) != FRAME_BYTES)) { - s->stats.rx_bad++; - printk(KERN_DEBUG "cs4297a: RX Bad attributes\n"); - } else { - s->stats.rx_good++; - if ((data >> 61) == 7) { - s->read_value = (data >> 12) & 0xffff; - s->read_reg = (data >> 40) & 0x7f; - wake_up(&d->reg_wait); - } - } - descr->descr_a &= ~M_DMA_SERRX_SOP; - descr++; - d->swptr++; - data_p += 4; - if (descr == d->descrtab_end) { - descr = d->descrtab; - d->swptr = 0; - data_p = d->dma_buf; - } - __raw_writeq(1, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - } while (--diff); - d->hwptr = hwptr; - - CS_DBGOUT(CS_DESCR, 6, - printk(KERN_INFO "cs4297a: hw/sw %x/%x\n", d->hwptr, d->swptr)); - } - - CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", - (unsigned)s, d->hwptr, - d->total_bytes, d->count)); - } - - /* XXXKW worry about s->reg_request -- there is a starvation - case if s->ena has FMODE_WRITE on, but the client isn't - doing writes */ - - // update DAC pointer - // - // check for end of buffer, means that we are going to wait for another interrupt - // to allow silence to fill the fifos on the part, to keep pops down to a minimum. - // - if (s->ena & FMODE_WRITE) { - serdma_t *d = &s->dma_dac; - hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - d->descrtab_phys) / sizeof(serdma_descr_t)); - diff = (d->ringsz + hwptr - d->hwptr) % d->ringsz; - CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): hw/hw/sw %x/%x/%x diff %d count %d\n", - d->hwptr, hwptr, d->swptr, diff, d->count)); - d->hwptr = hwptr; - /* XXXKW stereo? conversion? Just assume 2 16-bit samples for now */ - d->total_bytes += diff * FRAME_SAMPLE_BYTES; - if (d->mapped) { - d->count += diff * FRAME_SAMPLE_BYTES; - if (d->count >= d->fragsize) { - d->wakeup = 1; - wake_up(&d->wait); - if (d->count > d->sbufsz) - d->count &= d->sbufsz - 1; - } - } else { - d->count -= diff * FRAME_SAMPLE_BYTES; - if (d->count <= 0) { - // - // fill with silence, and do not shut down the DAC. - // Continue to play silence until the _release. - // - CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): memset %d at 0x%.8x for %d size \n", - (unsigned)(s->prop_dac.fmt & - (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, - (unsigned)d->dma_buf, - d->ringsz)); - memset(d->dma_buf, 0, d->ringsz * FRAME_BYTES); - if (d->count < 0) { - d->underrun = 1; - s->stats.tx_underrun++; - d->count = 0; - CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): underrun\n")); - } - } else if (d->count <= - (signed) d->fragsize - && !d->endcleared) { - /* XXXKW what is this for? */ - clear_advance(d->dma_buf, - d->sbufsz, - d->swptr, - d->fragsize, - 0); - d->endcleared = 1; - } - if ( (d->count <= (signed) d->sbufsz/2) || intflag) - { - CS_DBGOUT(CS_WAVE_WRITE, 4, - printk(KERN_INFO - "cs4297a: update count -> %d\n", d->count)); - wake_up(&d->wait); - } - } - CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO - "cs4297a: cs4297a_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", - (unsigned) s, d->hwptr, - d->total_bytes, d->count)); - } -} - -static int mixer_ioctl(struct cs4297a_state *s, unsigned int cmd, - unsigned long arg) -{ - // Index to mixer_src[] is value of AC97 Input Mux Select Reg. - // Value of array member is recording source Device ID Mask. - static const unsigned int mixer_src[8] = { - SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1, - SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0 - }; - - // Index of mixtable1[] member is Device ID - // and must be <= SOUND_MIXER_NRDEVICES. - // Value of array member is index into s->mix.vol[] - static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_PCM] = 1, // voice - [SOUND_MIXER_LINE1] = 2, // AUX - [SOUND_MIXER_CD] = 3, // CD - [SOUND_MIXER_LINE] = 4, // Line - [SOUND_MIXER_SYNTH] = 5, // FM - [SOUND_MIXER_MIC] = 6, // Mic - [SOUND_MIXER_SPEAKER] = 7, // Speaker - [SOUND_MIXER_RECLEV] = 8, // Recording level - [SOUND_MIXER_VOLUME] = 9 // Master Volume - }; - - static const unsigned mixreg[] = { - AC97_PCMOUT_VOL, - AC97_AUX_VOL, - AC97_CD_VOL, - AC97_LINEIN_VOL - }; - unsigned char l, r, rl, rr, vidx; - unsigned char attentbl[11] = - { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 }; - unsigned temp1; - int i, val; - - VALIDATE_STATE(s); - CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO - "cs4297a: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n", - (unsigned) s, cmd)); -#if CSDEBUG - cs_printioctl(cmd); -#endif -#if CSDEBUG_INTERFACE - - if ((cmd == SOUND_MIXER_CS_GETDBGMASK) || - (cmd == SOUND_MIXER_CS_SETDBGMASK) || - (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || - (cmd == SOUND_MIXER_CS_SETDBGLEVEL)) - { - switch (cmd) { - - case SOUND_MIXER_CS_GETDBGMASK: - return put_user(cs_debugmask, - (unsigned long *) arg); - - case SOUND_MIXER_CS_GETDBGLEVEL: - return put_user(cs_debuglevel, - (unsigned long *) arg); - - case SOUND_MIXER_CS_SETDBGMASK: - if (get_user(val, (unsigned long *) arg)) - return -EFAULT; - cs_debugmask = val; - return 0; - - case SOUND_MIXER_CS_SETDBGLEVEL: - if (get_user(val, (unsigned long *) arg)) - return -EFAULT; - cs_debuglevel = val; - return 0; - default: - CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO - "cs4297a: mixer_ioctl(): ERROR unknown debug cmd\n")); - return 0; - } - } -#endif - - if (cmd == SOUND_MIXER_PRIVATE1) { - return -EINVAL; - } - if (cmd == SOUND_MIXER_PRIVATE2) { - // enable/disable/query spatializer - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != -1) { - temp1 = (val & 0x3f) >> 2; - cs4297a_write_ac97(s, AC97_3D_CONTROL, temp1); - cs4297a_read_ac97(s, AC97_GENERAL_PURPOSE, - &temp1); - cs4297a_write_ac97(s, AC97_GENERAL_PURPOSE, - temp1 | 0x2000); - } - cs4297a_read_ac97(s, AC97_3D_CONTROL, &temp1); - return put_user((temp1 << 2) | 3, (int *) arg); - } - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "CS4297a", sizeof(info.id)); - strlcpy(info.name, "Crystal CS4297a", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user((void *) arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "CS4297a", sizeof(info.id)); - strlcpy(info.name, "Crystal CS4297a", sizeof(info.name)); - if (copy_to_user((void *) arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *) arg); - - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - // If ioctl has only the SIOC_READ bit(bit 31) - // on, process the only-read commands. - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source - cs4297a_read_ac97(s, AC97_RECORD_SELECT, - &temp1); - return put_user(mixer_src[temp1 & 7], (int *) arg); - - case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device - return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, - (int *) arg); - - case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source - return put_user(SOUND_MASK_LINE | SOUND_MASK_VOLUME, - (int *) arg); - - case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo - return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, - (int *) arg); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES - || !(vidx = mixtable1[i])) - return -EINVAL; - return put_user(s->mix.vol[vidx - 1], (int *) arg); - } - } - // If ioctl doesn't have both the SIOC_READ and - // the SIOC_WRITE bit set, return invalid. - if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE)) - return -EINVAL; - - // Increment the count of volume writes. - s->mix.modcnt++; - - // Isolate the command; it must be a write. - switch (_IOC_NR(cmd)) { - - case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source - if (get_user(val, (int *) arg)) - return -EFAULT; - i = hweight32(val); // i = # bits on in val. - if (i != 1) // One & only 1 bit must be on. - return 0; - for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) { - if (val == mixer_src[i]) { - temp1 = (i << 8) | i; - cs4297a_write_ac97(s, - AC97_RECORD_SELECT, - temp1); - return 0; - } - } - return 0; - - case SOUND_MIXER_VOLUME: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; // Max soundcard.h vol is 100. - if (l < 6) { - rl = 63; - l = 0; - } else - rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten. - - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; // Max right volume is 100, too - if (r < 6) { - rr = 63; - r = 0; - } else - rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation. - - if ((rl > 60) && (rr > 60)) // If both l & r are 'low', - temp1 = 0x8000; // turn on the mute bit. - else - temp1 = 0; - - temp1 |= (rl << 8) | rr; - - cs4297a_write_ac97(s, AC97_MASTER_VOL_STEREO, temp1); - cs4297a_write_ac97(s, AC97_PHONE_VOL, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[8] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[8] = val; -#endif - return put_user(s->mix.vol[8], (int *) arg); - - case SOUND_MIXER_SPEAKER: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 3) { - rl = 0; - l = 0; - } else { - rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15. - l = (rl * 13 + 5) / 2; - } - - if (rl < 3) { - temp1 = 0x8000; - rl = 0; - } else - temp1 = 0; - rl = 15 - rl; // Convert volume to attenuation. - temp1 |= rl << 1; - cs4297a_write_ac97(s, AC97_PCBEEP_VOL, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[6] = l << 8; -#else - s->mix.vol[6] = val; -#endif - return put_user(s->mix.vol[6], (int *) arg); - - case SOUND_MIXER_RECLEV: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15. - rr = (r * 2 - 5) / 13; - if (rl < 3 && rr < 3) - temp1 = 0x8000; - else - temp1 = 0; - - temp1 = temp1 | (rl << 8) | rr; - cs4297a_write_ac97(s, AC97_RECORD_GAIN, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[7] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[7] = val; -#endif - return put_user(s->mix.vol[7], (int *) arg); - - case SOUND_MIXER_MIC: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 1) { - l = 0; - rl = 0; - } else { - rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31. - l = (rl * 16 + 4) / 5; - } - cs4297a_read_ac97(s, AC97_MIC_VOL, &temp1); - temp1 &= 0x40; // Isolate 20db gain bit. - if (rl < 3) { - temp1 |= 0x8000; - rl = 0; - } - rl = 31 - rl; // Convert volume to attenuation. - temp1 |= rl; - cs4297a_write_ac97(s, AC97_MIC_VOL, temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[5] = val << 8; -#else - s->mix.vol[5] = val; -#endif - return put_user(s->mix.vol[5], (int *) arg); - - - case SOUND_MIXER_SYNTH: - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (get_user(val, (int *) arg)) - return -EFAULT; - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63. - rr = (r * 2 - 11) / 3; - if (rl < 3) // If l is low, turn on - temp1 = 0x0080; // the mute bit. - else - temp1 = 0; - - rl = 63 - rl; // Convert vol to attenuation. -// writel(temp1 | rl, s->pBA0 + FMLVC); - if (rr < 3) // If rr is low, turn on - temp1 = 0x0080; // the mute bit. - else - temp1 = 0; - rr = 63 - rr; // Convert vol to attenuation. -// writel(temp1 | rr, s->pBA0 + FMRVC); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[4] = (r << 8) | l; -#else - s->mix.vol[4] = val; -#endif - return put_user(s->mix.vol[4], (int *) arg); - - - default: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: mixer_ioctl(): default\n")); - - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) - return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - l = val & 0xff; - if (l > 100) - l = 100; - if (l < 1) { - l = 0; - rl = 31; - } else - rl = (attentbl[(l * 10) / 100]) >> 1; - - r = (val >> 8) & 0xff; - if (r > 100) - r = 100; - if (r < 1) { - r = 0; - rr = 31; - } else - rr = (attentbl[(r * 10) / 100]) >> 1; - if ((rl > 30) && (rr > 30)) - temp1 = 0x8000; - else - temp1 = 0; - temp1 = temp1 | (rl << 8) | rr; - cs4297a_write_ac97(s, mixreg[vidx - 1], temp1); - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l; -#else - s->mix.vol[vidx - 1] = val; -#endif - return put_user(s->mix.vol[vidx - 1], (int *) arg); - } -} - - -// --------------------------------------------------------------------- - -static int cs4297a_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct cs4297a_state *s=NULL; - struct list_head *entry; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, - printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); - - mutex_lock(&swarm_cs4297a_mutex); - list_for_each(entry, &cs4297a_devs) - { - s = list_entry(entry, struct cs4297a_state, list); - if(s->dev_mixer == minor) - break; - } - if (!s) - { - CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, - printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); - - mutex_unlock(&swarm_cs4297a_mutex); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, - printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); - mutex_unlock(&swarm_cs4297a_mutex); - - return nonseekable_open(inode, file); -} - - -static int cs4297a_release_mixdev(struct inode *inode, struct file *file) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - - VALIDATE_STATE(s); - return 0; -} - - -static int cs4297a_ioctl_mixdev(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ret; - mutex_lock(&swarm_cs4297a_mutex); - ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, - arg); - mutex_unlock(&swarm_cs4297a_mutex); - return ret; -} - - -// ****************************************************************************************** -// Mixer file operations struct. -// ****************************************************************************************** -static const struct file_operations cs4297a_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .unlocked_ioctl = cs4297a_ioctl_mixdev, - .open = cs4297a_open_mixdev, - .release = cs4297a_release_mixdev, -}; - -// --------------------------------------------------------------------- - - -static int drain_adc(struct cs4297a_state *s, int nonblock) -{ - /* This routine serves no purpose currently - any samples - sitting in the receive queue will just be processed by the - background consumer. This would be different if DMA - actually stopped when there were no clients. */ - return 0; -} - -static int drain_dac(struct cs4297a_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned hwptr; - unsigned tmo; - int count; - - if (s->dma_dac.mapped) - return 0; - if (nonblock) - return -EBUSY; - add_wait_queue(&s->dma_dac.wait, &wait); - while ((count = __raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) || - (s->dma_dac.count > 0)) { - if (!signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - /* XXXKW is this calculation working? */ - tmo = ((count * FRAME_TX_US) * HZ) / 1000000; - schedule_timeout(tmo + 1); - } else { - /* XXXKW do I care if there is a signal pending? */ - } - } - spin_lock_irqsave(&s->lock, flags); - /* Reset the bookkeeping */ - hwptr = (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); - s->dma_dac.hwptr = s->dma_dac.swptr = hwptr; - spin_unlock_irqrestore(&s->lock, flags); - remove_wait_queue(&s->dma_dac.wait, &wait); - __set_current_state(TASK_RUNNING); - return 0; -} - - -// --------------------------------------------------------------------- - -static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count, - loff_t * ppos) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - ssize_t ret; - unsigned long flags; - int cnt, count_fr, cnt_by; - unsigned copied = 0; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, - printk(KERN_INFO "cs4297a: cs4297a_read()+ %d \n", count)); - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; -// -// "count" is the amount of bytes to read (from app), is decremented each loop -// by the amount of bytes that have been returned to the user buffer. -// "cnt" is the running total of each read from the buffer (changes each loop) -// "buffer" points to the app's buffer -// "ret" keeps a running total of the amount of bytes that have been copied -// to the user buffer. -// "copied" is the total bytes copied into the user buffer for each loop. -// - while (count > 0) { - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - "_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n", - count, s->dma_adc.count, - s->dma_adc.swptr, s->dma_adc.hwptr)); - spin_lock_irqsave(&s->lock, flags); - - /* cnt will be the number of available samples (16-bit - stereo); it starts out as the maxmimum consequetive - samples */ - cnt = (s->dma_adc.sb_end - s->dma_adc.sb_swptr) / 2; - count_fr = s->dma_adc.count / FRAME_SAMPLE_BYTES; - - // dma_adc.count is the current total bytes that have not been read. - // if the amount of unread bytes from the current sw pointer to the - // end of the buffer is greater than the current total bytes that - // have not been read, then set the "cnt" (unread bytes) to the - // amount of unread bytes. - - if (count_fr < cnt) - cnt = count_fr; - cnt_by = cnt * FRAME_SAMPLE_BYTES; - spin_unlock_irqrestore(&s->lock, flags); - // - // if we are converting from 8/16 then we need to copy - // twice the number of 16 bit bytes then 8 bit bytes. - // - if (s->conversion) { - if (cnt_by > (count * 2)) { - cnt = (count * 2) / FRAME_SAMPLE_BYTES; - cnt_by = count * 2; - } - } else { - if (cnt_by > count) { - cnt = count / FRAME_SAMPLE_BYTES; - cnt_by = count; - } - } - // - // "cnt" NOW is the smaller of the amount that will be read, - // and the amount that is requested in this read (or partial). - // if there are no bytes in the buffer to read, then start the - // ADC and wait for the interrupt handler to wake us up. - // - if (cnt <= 0) { - - // start up the dma engine and then continue back to the top of - // the loop when wake up occurs. - start_adc(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - oss_broken_sleep_on(&s->dma_adc.wait, MAX_SCHEDULE_TIMEOUT); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - // there are bytes in the buffer to read. - // copy from the hw buffer over to the user buffer. - // user buffer is designated by "buffer" - // virtual address to copy from is dma_buf+swptr - // the "cnt" is the number of bytes to read. - - CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO - "_read() copy_to cnt=%d count=%d ", cnt_by, count)); - CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO - " .sbufsz=%d .count=%d buffer=0x%.8x ret=%d\n", - s->dma_adc.sbufsz, s->dma_adc.count, - (unsigned) buffer, ret)); - - if (copy_to_user (buffer, ((void *)s->dma_adc.sb_swptr), cnt_by)) - return ret ? ret : -EFAULT; - copied = cnt_by; - - /* Return the descriptors */ - spin_lock_irqsave(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: upd_rcv sw->hw %x/%x\n", s->dma_adc.swptr, s->dma_adc.hwptr)); - s->dma_adc.count -= cnt_by; - s->dma_adc.sb_swptr += cnt * 2; - if (s->dma_adc.sb_swptr == s->dma_adc.sb_end) - s->dma_adc.sb_swptr = s->dma_adc.sample_buf; - spin_unlock_irqrestore(&s->lock, flags); - count -= copied; - buffer += copied; - ret += copied; - start_adc(s); - } - CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, - printk(KERN_INFO "cs4297a: cs4297a_read()- %d\n", ret)); - return ret; -} - - -static ssize_t cs4297a_write(struct file *file, const char *buffer, - size_t count, loff_t * ppos) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr, hwptr; - int cnt; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, - printk(KERN_INFO "cs4297a: cs4297a_write()+ count=%d\n", - count)); - VALIDATE_STATE(s); - - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - while (count > 0) { - serdma_t *d = &s->dma_dac; - int copy_cnt; - u32 *s_tmpl; - u32 *t_tmpl; - u32 left, right; - int swap = (s->prop_dac.fmt == AFMT_S16_LE) || (s->prop_dac.fmt == AFMT_U16_LE); - - /* XXXXXX this is broken for BLOAT_FACTOR */ - spin_lock_irqsave(&s->lock, flags); - if (d->count < 0) { - d->count = 0; - d->swptr = d->hwptr; - } - if (d->underrun) { - d->underrun = 0; - hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - d->descrtab_phys) / sizeof(serdma_descr_t)); - d->swptr = d->hwptr = hwptr; - } - swptr = d->swptr; - cnt = d->sbufsz - (swptr * FRAME_SAMPLE_BYTES); - /* Will this write fill up the buffer? */ - if (d->count + cnt > d->sbufsz) - cnt = d->sbufsz - d->count; - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - start_dac(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - oss_broken_sleep_on(&d->wait, MAX_SCHEDULE_TIMEOUT); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; - continue; - } - if (copy_from_user(d->sample_buf, buffer, cnt)) - return ret ? ret : -EFAULT; - - copy_cnt = cnt; - s_tmpl = (u32 *)d->sample_buf; - t_tmpl = (u32 *)(d->dma_buf + (swptr * 4)); - - /* XXXKW assuming 16-bit stereo! */ - do { - u32 tmp; - - t_tmpl[0] = cpu_to_be32(0x98000000); - - tmp = be32_to_cpu(s_tmpl[0]); - left = tmp & 0xffff; - right = tmp >> 16; - if (swap) { - left = swab16(left); - right = swab16(right); - } - t_tmpl[1] = cpu_to_be32(left >> 8); - t_tmpl[2] = cpu_to_be32(((left & 0xff) << 24) | - (right << 4)); - - s_tmpl++; - t_tmpl += 8; - copy_cnt -= 4; - } while (copy_cnt); - - /* Mux in any pending read/write accesses */ - if (s->reg_request) { - *(u64 *)(d->dma_buf + (swptr * 4)) |= - cpu_to_be64(s->reg_request); - s->reg_request = 0; - wake_up(&s->dma_dac.reg_wait); - } - - CS_DBGOUT(CS_WAVE_WRITE, 4, - printk(KERN_INFO - "cs4297a: copy in %d to swptr %x\n", cnt, swptr)); - - swptr = (swptr + (cnt/FRAME_SAMPLE_BYTES)) % d->ringsz; - __raw_writeq(cnt/FRAME_SAMPLE_BYTES, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); - spin_lock_irqsave(&s->lock, flags); - d->swptr = swptr; - d->count += cnt; - d->endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_dac(s); - } - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, - printk(KERN_INFO "cs4297a: cs4297a_write()- %d\n", ret)); - return ret; -} - - -static unsigned int cs4297a_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - unsigned long flags; - unsigned int mask = 0; - - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4297a: cs4297a_poll()+\n")); - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4297a: cs4297a_poll() wait on FMODE_WRITE\n")); - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO - "cs4297a: cs4297a_poll() wait on FMODE_READ\n")); - if(!s->dma_dac.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= - (signed) s->dma_dac.fragsize) { - if (s->dma_dac.wakeup) - mask |= POLLOUT | POLLWRNORM; - else - mask = 0; - s->dma_dac.wakeup = 0; - } - } else { - if ((signed) (s->dma_dac.sbufsz/2) >= s->dma_dac.count) - mask |= POLLOUT | POLLWRNORM; - } - } else if (file->f_mode & FMODE_READ) { - if (s->dma_adc.mapped) { - if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } else { - if (s->dma_adc.count > 0) - mask |= POLLIN | POLLRDNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4297a: cs4297a_poll()- 0x%.8x\n", - mask)); - return mask; -} - - -static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* XXXKW currently no mmap support */ - return -EINVAL; - return 0; -} - - -static int cs4297a_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - - CS_DBGOUT(CS_FUNCTION|CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): file=0x%.8x cmd=0x%.8x\n", - (unsigned) file, cmd)); -#if CSDEBUG - cs_printioctl(cmd); -#endif - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): SOUND_VERSION=0x%.8x\n", - SOUND_VERSION)); - return put_user(SOUND_VERSION, (int *) arg); - - case SNDCTL_DSP_SYNC: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SYNC\n")); - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, - 0 /*file->f_flags & O_NONBLOCK */ - ); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, - (int *) arg); - - case SNDCTL_DSP_RESET: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_RESET\n")); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->irq); - s->dma_dac.count = s->dma_dac.total_bytes = - s->dma_dac.blocks = s->dma_dac.wakeup = 0; - s->dma_dac.swptr = s->dma_dac.hwptr = - (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - - s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.count = s->dma_adc.total_bytes = - s->dma_adc.blocks = s->dma_dac.wakeup = 0; - s->dma_adc.swptr = s->dma_adc.hwptr = - (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - - s->dma_adc.descrtab_phys) / sizeof(serdma_descr_t)); - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SPEED val=%d -> 48000\n", val)); - val = 48000; - return put_user(val, (int *) arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_STEREO val=%d\n", val)); - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - s->prop_adc.channels = val ? 2 : 1; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - s->prop_dac.channels = val ? 2 : 1; - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_CHANNELS val=%d\n", - val)); - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - s->prop_adc.channels = 2; - else - s->prop_adc.channels = 1; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - s->prop_dac.channels = 2; - else - s->prop_dac.channels = 1; - } - } - - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.channels; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.channels; - - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETFMTS: // Returns a mask - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_GETFMT val=0x%.8x\n", - AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8)); - return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 | - AFMT_U8, (int *) arg); - - case SNDCTL_DSP_SETFMT: - if (get_user(val, (int *) arg)) - return -EFAULT; - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SETFMT val=0x%.8x\n", - val)); - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val != AFMT_S16_LE - && val != AFMT_U16_LE && val != AFMT_S8 - && val != AFMT_U8) - val = AFMT_U8; - s->prop_adc.fmt = val; - s->prop_adc.fmt_original = s->prop_adc.fmt; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val != AFMT_S16_LE - && val != AFMT_U16_LE && val != AFMT_S8 - && val != AFMT_U8) - val = AFMT_U8; - s->prop_dac.fmt = val; - s->prop_dac.fmt_original = s->prop_dac.fmt; - } - } else { - if (file->f_mode & FMODE_WRITE) - val = s->prop_dac.fmt_original; - else if (file->f_mode & FMODE_READ) - val = s->prop_adc.fmt_original; - } - CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_SETFMT return val=0x%.8x\n", - val)); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_POST: - CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): DSP_POST\n")); - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & s->ena & FMODE_READ) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & s->ena & FMODE_WRITE) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, (int *) arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready - && (ret = prog_dmabuf_adc(s))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready - && (ret = prog_dmabuf_dac(s))) - return ret; - start_dac(s); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s))) - return val; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - abinfo.fragsize = s->dma_dac.fragsize; - if (s->dma_dac.mapped) - abinfo.bytes = s->dma_dac.sbufsz; - else - abinfo.bytes = - s->dma_dac.sbufsz - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO - "cs4297a: cs4297a_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n", - abinfo.fragsize,abinfo.bytes,abinfo.fragstotal, - abinfo.fragments)); - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s))) - return val; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - if (s->conversion) { - abinfo.fragsize = s->dma_adc.fragsize / 2; - abinfo.bytes = s->dma_adc.count / 2; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = - abinfo.bytes >> (s->dma_adc.fragshift - 1); - } else { - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = - abinfo.bytes >> s->dma_adc.fragshift; - } - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if(!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - cinfo.bytes = s->dma_adc.total_bytes; - if (s->dma_adc.mapped) { - cinfo.blocks = - (cinfo.bytes >> s->dma_adc.fragshift) - - s->dma_adc.blocks; - s->dma_adc.blocks = - cinfo.bytes >> s->dma_adc.fragshift; - } else { - if (s->conversion) { - cinfo.blocks = - s->dma_adc.count / - 2 >> (s->dma_adc.fragshift - 1); - } else - cinfo.blocks = - s->dma_adc.count >> s->dma_adc. - fragshift; - } - if (s->conversion) - cinfo.ptr = s->dma_adc.hwptr / 2; - else - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize - 1; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if(!s->dma_dac.ready && prog_dmabuf_dac(s)) - return 0; - spin_lock_irqsave(&s->lock, flags); - cs4297a_update_ptr(s,CS_FALSE); - cinfo.bytes = s->dma_dac.total_bytes; - if (s->dma_dac.mapped) { - cinfo.blocks = - (cinfo.bytes >> s->dma_dac.fragshift) - - s->dma_dac.blocks; - s->dma_dac.blocks = - cinfo.bytes >> s->dma_dac.fragshift; - } else { - cinfo.blocks = - s->dma_dac.count >> s->dma_dac.fragshift; - } - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize - 1; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac(s))) - return val; - return put_user(s->dma_dac.fragsize, (int *) arg); - } - if ((val = prog_dmabuf_adc(s))) - return val; - if (s->conversion) - return put_user(s->dma_adc.fragsize / 2, - (int *) arg); - else - return put_user(s->dma_adc.fragsize, (int *) arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *) arg)) - return -EFAULT; - return 0; // Say OK, but do nothing. - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) - || (file->f_mode & FMODE_WRITE - && s->dma_dac.subdivision)) return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - else if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - if (file->f_mode & FMODE_READ) - return put_user(s->prop_adc.rate, (int *) arg); - else if (file->f_mode & FMODE_WRITE) - return put_user(s->prop_dac.rate, (int *) arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user(s->prop_adc.channels, (int *) arg); - else if (file->f_mode & FMODE_WRITE) - return put_user(s->prop_dac.channels, (int *) arg); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return - put_user( - (s->prop_adc. - fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, - (int *) arg); - else if (file->f_mode & FMODE_WRITE) - return - put_user( - (s->prop_dac. - fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16, - (int *) arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - return mixer_ioctl(s, cmd, arg); -} - -static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) -{ - int ret; - - mutex_lock(&swarm_cs4297a_mutex); - ret = cs4297a_ioctl(file, cmd, arg); - mutex_unlock(&swarm_cs4297a_mutex); - - return ret; -} - -static int cs4297a_release(struct inode *inode, struct file *file) -{ - struct cs4297a_state *s = - (struct cs4297a_state *) file->private_data; - - CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO - "cs4297a: cs4297a_release(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n", - (unsigned) inode, (unsigned) file, file->f_mode)); - VALIDATE_STATE(s); - - if (file->f_mode & FMODE_WRITE) { - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_sem_dac); - stop_dac(s); - dealloc_dmabuf(s, &s->dma_dac); - s->open_mode &= ~FMODE_WRITE; - mutex_unlock(&s->open_sem_dac); - wake_up(&s->open_wait_dac); - } - if (file->f_mode & FMODE_READ) { - drain_adc(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_sem_adc); - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - s->open_mode &= ~FMODE_READ; - mutex_unlock(&s->open_sem_adc); - wake_up(&s->open_wait_adc); - } - return 0; -} - -static int cs4297a_locked_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct cs4297a_state *s=NULL; - struct list_head *entry; - - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4297a: cs4297a_open(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n", - (unsigned) inode, (unsigned) file, file->f_mode)); - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4297a: status = %08x\n", (int)__raw_readq(SS_CSR(R_SER_STATUS_DEBUG)))); - - list_for_each(entry, &cs4297a_devs) - { - s = list_entry(entry, struct cs4297a_state, list); - - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - if (entry == &cs4297a_devs) - return -ENODEV; - if (!s) { - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO - "cs4297a: cs4297a_open(): Error - unable to find audio state struct\n")); - return -ENODEV; - } - VALIDATE_STATE(s); - file->private_data = s; - - // wait for device to become free - if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) { - CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO - "cs4297a: cs4297a_open(): Error - must open READ and/or WRITE\n")); - return -ENODEV; - } - if (file->f_mode & FMODE_WRITE) { - if (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX)) != 0) { - printk(KERN_ERR "cs4297a: TX pipe needs to drain\n"); - while (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) - ; - } - - mutex_lock(&s->open_sem_dac); - while (s->open_mode & FMODE_WRITE) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem_dac); - return -EBUSY; - } - mutex_unlock(&s->open_sem_dac); - oss_broken_sleep_on(&s->open_wait_dac, MAX_SCHEDULE_TIMEOUT); - - if (signal_pending(current)) { - printk("open - sig pending\n"); - return -ERESTARTSYS; - } - mutex_lock(&s->open_sem_dac); - } - } - if (file->f_mode & FMODE_READ) { - mutex_lock(&s->open_sem_adc); - while (s->open_mode & FMODE_READ) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_sem_adc); - return -EBUSY; - } - mutex_unlock(&s->open_sem_adc); - oss_broken_sleep_on(&s->open_wait_adc, MAX_SCHEDULE_TIMEOUT); - - if (signal_pending(current)) { - printk("open - sig pending\n"); - return -ERESTARTSYS; - } - mutex_lock(&s->open_sem_adc); - } - } - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - if (file->f_mode & FMODE_READ) { - s->prop_adc.fmt = AFMT_S16_BE; - s->prop_adc.fmt_original = s->prop_adc.fmt; - s->prop_adc.channels = 2; - s->prop_adc.rate = 48000; - s->conversion = 0; - s->ena &= ~FMODE_READ; - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = 0; - mutex_unlock(&s->open_sem_adc); - - if (prog_dmabuf_adc(s)) { - CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR - "cs4297a: adc Program dmabufs failed.\n")); - cs4297a_release(inode, file); - return -ENOMEM; - } - } - if (file->f_mode & FMODE_WRITE) { - s->prop_dac.fmt = AFMT_S16_BE; - s->prop_dac.fmt_original = s->prop_dac.fmt; - s->prop_dac.channels = 2; - s->prop_dac.rate = 48000; - s->conversion = 0; - s->ena &= ~FMODE_WRITE; - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = 0; - mutex_unlock(&s->open_sem_dac); - - if (prog_dmabuf_dac(s)) { - CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR - "cs4297a: dac Program dmabufs failed.\n")); - cs4297a_release(inode, file); - return -ENOMEM; - } - } - CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, - printk(KERN_INFO "cs4297a: cs4297a_open()- 0\n")); - return nonseekable_open(inode, file); -} - -static int cs4297a_open(struct inode *inode, struct file *file) -{ - int ret; - - mutex_lock(&swarm_cs4297a_mutex); - ret = cs4297a_open(inode, file); - mutex_unlock(&swarm_cs4297a_mutex); - - return ret; -} - -// ****************************************************************************************** -// Wave (audio) file operations struct. -// ****************************************************************************************** -static const struct file_operations cs4297a_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cs4297a_read, - .write = cs4297a_write, - .poll = cs4297a_poll, - .unlocked_ioctl = cs4297a_unlocked_ioctl, - .mmap = cs4297a_mmap, - .open = cs4297a_open, - .release = cs4297a_release, -}; - -static void cs4297a_interrupt(int irq, void *dev_id) -{ - struct cs4297a_state *s = (struct cs4297a_state *) dev_id; - u32 status; - - status = __raw_readq(SS_CSR(R_SER_STATUS_DEBUG)); - - CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO - "cs4297a: cs4297a_interrupt() HISR=0x%.8x\n", status)); - -#if 0 - /* XXXKW what check *should* be done here? */ - if (!(status & (M_SYNCSER_RX_EOP_COUNT | M_SYNCSER_RX_OVERRUN | M_SYNCSER_RX_SYNC_ERR))) { - status = __raw_readq(SS_CSR(R_SER_STATUS)); - printk(KERN_ERR "cs4297a: unexpected interrupt (status %08x)\n", status); - return; - } -#endif - - if (status & M_SYNCSER_RX_SYNC_ERR) { - status = __raw_readq(SS_CSR(R_SER_STATUS)); - printk(KERN_ERR "cs4297a: rx sync error (status %08x)\n", status); - return; - } - - if (status & M_SYNCSER_RX_OVERRUN) { - int newptr, i; - s->stats.rx_ovrrn++; - printk(KERN_ERR "cs4297a: receive FIFO overrun\n"); - - /* Fix things up: get the receive descriptor pool - clean and give them back to the hardware */ - while (__raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_RX))) - ; - newptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_RX)) & M_DMA_CURDSCR_ADDR) - - s->dma_adc.descrtab_phys) / sizeof(serdma_descr_t)); - for (i=0; i<DMA_DESCR; i++) { - s->dma_adc.descrtab[i].descr_a &= ~M_DMA_SERRX_SOP; - } - s->dma_adc.swptr = s->dma_adc.hwptr = newptr; - s->dma_adc.count = 0; - s->dma_adc.sb_swptr = s->dma_adc.sb_hwptr = s->dma_adc.sample_buf; - __raw_writeq(DMA_DESCR, SS_CSR(R_SER_DMA_DSCR_COUNT_RX)); - } - - spin_lock(&s->lock); - cs4297a_update_ptr(s,CS_TRUE); - spin_unlock(&s->lock); - - CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO - "cs4297a: cs4297a_interrupt()-\n")); -} - -#if 0 -static struct initvol { - int mixch; - int vol; -} initvol[] __initdata = { - - {SOUND_MIXER_WRITE_VOLUME, 0x4040}, - {SOUND_MIXER_WRITE_PCM, 0x4040}, - {SOUND_MIXER_WRITE_SYNTH, 0x4040}, - {SOUND_MIXER_WRITE_CD, 0x4040}, - {SOUND_MIXER_WRITE_LINE, 0x4040}, - {SOUND_MIXER_WRITE_LINE1, 0x4040}, - {SOUND_MIXER_WRITE_RECLEV, 0x0000}, - {SOUND_MIXER_WRITE_SPEAKER, 0x4040}, - {SOUND_MIXER_WRITE_MIC, 0x0000} -}; -#endif - -static int __init cs4297a_init(void) -{ - struct cs4297a_state *s; - u32 pwr, id; - mm_segment_t fs; - int rval; - u64 cfg; - int mdio_val; - - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO - "cs4297a: cs4297a_init_module()+ \n")); - - mdio_val = __raw_readq(KSEG1 + A_MAC_REGISTER(2, R_MAC_MDIO)) & - (M_MAC_MDIO_DIR|M_MAC_MDIO_OUT); - - /* Check syscfg for synchronous serial on port 1 */ - cfg = __raw_readq(KSEG1 + A_SCD_SYSTEM_CFG); - if (!(cfg & M_SYS_SER1_ENABLE)) { - __raw_writeq(cfg | M_SYS_SER1_ENABLE, KSEG1+A_SCD_SYSTEM_CFG); - cfg = __raw_readq(KSEG1 + A_SCD_SYSTEM_CFG); - if (!(cfg & M_SYS_SER1_ENABLE)) { - printk(KERN_INFO "cs4297a: serial port 1 not configured for synchronous operation\n"); - return -1; - } - - printk(KERN_INFO "cs4297a: serial port 1 switching to synchronous operation\n"); - - /* Force the codec (on SWARM) to reset by clearing - GENO, preserving MDIO (no effect on CSWARM) */ - __raw_writeq(mdio_val, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO)); - udelay(10); - } - - /* Now set GENO */ - __raw_writeq(mdio_val | M_MAC_GENC, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO)); - /* Give the codec some time to finish resetting (start the bit clock) */ - udelay(100); - - if (!(s = kzalloc(sizeof(struct cs4297a_state), GFP_KERNEL))) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4297a: probe() no memory for state struct.\n")); - return -1; - } - s->magic = CS4297a_MAGIC; - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->dma_adc.reg_wait); - init_waitqueue_head(&s->dma_dac.reg_wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->open_wait_adc); - init_waitqueue_head(&s->open_wait_dac); - mutex_init(&s->open_sem_adc); - mutex_init(&s->open_sem_dac); - spin_lock_init(&s->lock); - - s->irq = K_INT_SER_1; - - if (request_irq - (s->irq, cs4297a_interrupt, 0, "Crystal CS4297a", s)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, - printk(KERN_ERR "cs4297a: irq %u in use\n", s->irq)); - goto err_irq; - } - if ((s->dev_audio = register_sound_dsp(&cs4297a_audio_fops, -1)) < - 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4297a: probe() register_sound_dsp() failed.\n")); - goto err_dev1; - } - if ((s->dev_mixer = register_sound_mixer(&cs4297a_mixer_fops, -1)) < - 0) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4297a: probe() register_sound_mixer() failed.\n")); - goto err_dev2; - } - - if (ser_init(s) || dma_init(s)) { - CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR - "cs4297a: ser_init failed.\n")); - goto err_dev3; - } - - do { - udelay(4000); - rval = cs4297a_read_ac97(s, AC97_POWER_CONTROL, &pwr); - } while (!rval && (pwr != 0xf)); - - if (!rval) { - char *sb1250_duart_present; - - fs = get_fs(); - set_fs(KERNEL_DS); -#if 0 - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val); - for (i = 0; i < ARRAY_SIZE(initvol); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val); - } -// cs4297a_write_ac97(s, 0x18, 0x0808); -#else - // cs4297a_write_ac97(s, 0x5e, 0x180); - cs4297a_write_ac97(s, 0x02, 0x0808); - cs4297a_write_ac97(s, 0x18, 0x0808); -#endif - set_fs(fs); - - list_add(&s->list, &cs4297a_devs); - - cs4297a_read_ac97(s, AC97_VENDOR_ID1, &id); - - sb1250_duart_present = symbol_get(sb1250_duart_present); - if (sb1250_duart_present) - sb1250_duart_present[1] = 0; - - printk(KERN_INFO "cs4297a: initialized (vendor id = %x)\n", id); - - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: cs4297a_init_module()-\n")); - - return 0; - } - - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - free_irq(s->irq, s); - err_irq: - kfree(s); - - printk(KERN_INFO "cs4297a: initialization failed\n"); - - return -1; -} - -static void __exit cs4297a_cleanup(void) -{ - /* - XXXKW - disable_irq, free_irq - drain DMA queue - disable DMA - disable TX/RX - free memory - */ - CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, - printk(KERN_INFO "cs4297a: cleanup_cs4297a() finished\n")); -} - -// --------------------------------------------------------------------- - -MODULE_AUTHOR("Kip Walker, Broadcom Corp."); -MODULE_DESCRIPTION("Cirrus Logic CS4297a Driver for Broadcom SWARM board"); - -// --------------------------------------------------------------------- - -module_init(cs4297a_init); -module_exit(cs4297a_cleanup); diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c deleted file mode 100644 index d17019d25b99..000000000000 --- a/sound/oss/sys_timer.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * sound/oss/sys_timer.c - * - * The default timer for the Level 2 sequencer interface - * Uses the (1/HZ sec) timer of kernel. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow) - */ -#include <linux/spinlock.h> -#include "sound_config.h" - -static volatile int opened, tmr_running; -static volatile unsigned int tmr_offs, tmr_ctr; -static volatile unsigned long ticks_offs; -static volatile int curr_tempo, curr_timebase; -static volatile unsigned long curr_ticks; -static volatile unsigned long next_event_time; -static unsigned long prev_event_time; - -static void poll_def_tmr(unsigned long dummy); -static DEFINE_SPINLOCK(lock); -static DEFINE_TIMER(def_tmr, poll_def_tmr, 0, 0); - -static unsigned long -tmr2ticks(int tmr_value) -{ - /* - * Convert timer ticks to MIDI ticks - */ - - unsigned long tmp; - unsigned long scale; - - /* tmr_value (ticks per sec) * - 1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */ - tmp = tmr_value * (1000000 / HZ); - scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ - return (tmp + scale / 2) / scale; -} - -static void -poll_def_tmr(unsigned long dummy) -{ - if (!opened) - return; - def_tmr.expires = (1) + jiffies; - add_timer(&def_tmr); - - if (!tmr_running) - return; - - spin_lock(&lock); - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - - if (curr_ticks >= next_event_time) { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } - - spin_unlock(&lock); -} - -static void -tmr_reset(void) -{ - unsigned long flags; - - spin_lock_irqsave(&lock,flags); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - spin_unlock_irqrestore(&lock,flags); -} - -static int -def_tmr_open(int dev, int mode) -{ - if (opened) - return -EBUSY; - - tmr_reset(); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - { - def_tmr.expires = (1) + jiffies; - add_timer(&def_tmr); - } - - return 0; -} - -static void -def_tmr_close(int dev) -{ - opened = tmr_running = 0; - del_timer(&def_tmr); -} - -static int -def_tmr_event(int dev, unsigned char *event) -{ - unsigned char cmd = event[1]; - unsigned long parm = *(int *) &event[4]; - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - tmr_reset(); - tmr_running = 1; - break; - - case TMR_STOP: - tmr_running = 0; - break; - - case TMR_CONTINUE: - tmr_running = 1; - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 360) - parm = 360; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks(tmr_ctr); - tmr_ctr = 0; - curr_tempo = parm; - } - break; - - case TMR_ECHO: - seq_copy_to_input(event, 8); - break; - - default:; - } - - return TIMER_NOT_ARMED; -} - -static unsigned long -def_tmr_get_time(int dev) -{ - if (!opened) - return 0; - - return curr_ticks; -} - -/* same as sound_timer.c:timer_ioctl!? */ -static int def_tmr_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - int __user *p = arg; - int val; - - switch (cmd) { - case SNDCTL_TMR_SOURCE: - return __put_user(TMR_INTERNAL, p); - - case SNDCTL_TMR_START: - tmr_reset(); - tmr_running = 1; - return 0; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - - case SNDCTL_TMR_TIMEBASE: - if (__get_user(val, p)) - return -EFAULT; - if (val) { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - return __put_user(curr_timebase, p); - - case SNDCTL_TMR_TEMPO: - if (__get_user(val, p)) - return -EFAULT; - if (val) { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks(tmr_ctr); - tmr_ctr = 0; - curr_tempo = val; - reprogram_timer(); - } - return __put_user(curr_tempo, p); - - case SNDCTL_SEQ_CTRLRATE: - if (__get_user(val, p)) - return -EFAULT; - if (val != 0) /* Can't change */ - return -EINVAL; - val = ((curr_tempo * curr_timebase) + 30) / 60; - return __put_user(val, p); - - case SNDCTL_SEQ_GETTIME: - return __put_user(curr_ticks, p); - - case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - - default:; - } - return -EINVAL; -} - -static void -def_tmr_arm(int dev, long time) -{ - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; - - next_event_time = prev_event_time = time; - - return; -} - -struct sound_timer_operations default_sound_timer = -{ - .owner = THIS_MODULE, - .info = {"System clock", 0}, - .priority = 0, /* Priority */ - .devlink = 0, /* Local device link */ - .open = def_tmr_open, - .close = def_tmr_close, - .event = def_tmr_event, - .get_time = def_tmr_get_time, - .ioctl = def_tmr_ioctl, - .arm_timer = def_tmr_arm -}; diff --git a/sound/oss/trix.c b/sound/oss/trix.c deleted file mode 100644 index a57bc635d758..000000000000 --- a/sound/oss/trix.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * sound/oss/trix.c - * - * Low level driver for the MediaTrix AudioTrix Pro - * (MT-0002-PC Control Chip) - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes - * Alan Cox Modularisation, cleanup. - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo Got rid of attach_uart401 - */ - -#include <linux/init.h> -#include <linux/module.h> - -#include "sound_config.h" -#include "sb.h" -#include "sound_firmware.h" - -#include "ad1848.h" -#include "mpu401.h" - -#include "trix_boot.h" - -static int mpu; - -static bool joystick; - -static unsigned char trix_read(int addr) -{ - outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ - return inb(0x391); /* MT-0002-PC ASIC data */ -} - -static void trix_write(int addr, int data) -{ - outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ - outb(((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ -} - -static void download_boot(int base) -{ - int i = 0, n = trix_boot_len; - - if (trix_boot_len == 0) - return; - - trix_write(0xf8, 0x00); /* ??????? */ - outb((0x01), base + 6); /* Clear the internal data pointer */ - outb((0x00), base + 6); /* Restart */ - - /* - * Write the boot code to the RAM upload/download register. - * Each write increments the internal data pointer. - */ - outb((0x01), base + 6); /* Clear the internal data pointer */ - outb((0x1A), 0x390); /* Select RAM download/upload port */ - - for (i = 0; i < n; i++) - outb((trix_boot[i]), 0x391); - for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ - outb((0x00), 0x391); - outb((0x00), base + 6); /* Reset */ - outb((0x50), 0x390); /* ?????? */ - -} - -static int trix_set_wss_port(struct address_info *hw_config) -{ - unsigned char addr_bits; - - if (trix_read(0x15) != 0x71) /* No ASIC signature */ - { - MDB(printk(KERN_ERR "No AudioTrix ASIC signature found\n")); - return 0; - } - - /* - * Reset some registers. - */ - - trix_write(0x13, 0); - trix_write(0x14, 0); - - /* - * Configure the ASIC to place the codec to the proper I/O location - */ - - switch (hw_config->io_base) - { - case 0x530: - addr_bits = 0; - break; - case 0x604: - addr_bits = 1; - break; - case 0xE80: - addr_bits = 2; - break; - case 0xF40: - addr_bits = 3; - break; - default: - return 0; - } - - trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits); - return 1; -} - -/* - * Probe and attach routines for the Windows Sound System mode of - * AudioTrix Pro - */ - -static int __init init_trix_wss(struct address_info *hw_config) -{ - static unsigned char dma_bits[4] = { - 1, 2, 0, 3 - }; - struct resource *ports; - int config_port = hw_config->io_base + 0; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; - u8 config, bits; - int ret; - - switch(hw_config->irq) { - case 7: - bits = 8; - break; - case 9: - bits = 0x10; - break; - case 10: - bits = 0x18; - break; - case 11: - bits = 0x20; - break; - default: - printk(KERN_ERR "AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); - return 0; - } - - switch (dma1) { - case 0: - case 1: - case 3: - break; - default: - printk(KERN_ERR "AudioTrix: Bad WSS DMA %d\n", dma1); - return 0; - } - - switch (dma2) { - case -1: - case 0: - case 1: - case 3: - break; - default: - printk(KERN_ERR "AudioTrix: Bad capture DMA %d\n", dma2); - return 0; - } - - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. - */ - ports = request_region(hw_config->io_base + 4, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if (!request_region(hw_config->io_base, 4, "MSS config")) { - printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - release_region(hw_config->io_base + 4, 4); - return 0; - } - - if (!trix_set_wss_port(hw_config)) - goto fail; - - config = inb(hw_config->io_base + 3); - - if ((config & 0x3f) != 0x00) - { - MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x\n", hw_config->io_base)); - goto fail; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (dma1 == 0 && config & 0x80) - { - printk(KERN_ERR "AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); - goto fail; - } - if (hw_config->irq > 9 && config & 0x80) - { - printk(KERN_ERR "AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); - goto fail; - } - - ret = ad1848_detect(ports, NULL, hw_config->osp); - if (!ret) - goto fail; - - if (joystick==1) - trix_write(0x15, 0x80); - - /* - * Set the IRQ and DMA addresses. - */ - - outb((bits | 0x40), config_port); - - if (dma2 == -1 || dma2 == dma1) - { - bits |= dma_bits[dma1]; - dma2 = dma1; - } - else - { - unsigned char tmp; - - tmp = trix_read(0x13) & ~30; - trix_write(0x13, tmp | 0x80 | (dma1 << 4)); - - tmp = trix_read(0x14) & ~30; - trix_write(0x14, tmp | 0x80 | (dma2 << 4)); - } - - outb((bits), config_port); /* Write IRQ+DMA setup */ - - hw_config->slots[0] = ad1848_init("AudioTrix Pro", ports, - hw_config->irq, - dma1, - dma2, - 0, - hw_config->osp, - THIS_MODULE); - - if (num_mixers > old_num_mixers) /* Mixer got installed */ - { - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ - AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ - } - return 1; - -fail: - release_region(hw_config->io_base, 4); - release_region(hw_config->io_base + 4, 4); - return 0; -} - -static int __init probe_trix_sb(struct address_info *hw_config) -{ - - int tmp; - unsigned char conf; - extern int sb_be_quiet; - int old_quiet; - static signed char irq_translate[] = { - -1, -1, -1, 0, 1, 2, -1, 3 - }; - - if (trix_boot_len == 0) - return 0; /* No boot code -> no fun */ - - if ((hw_config->io_base & 0xffffff8f) != 0x200) - return 0; - - tmp = hw_config->irq; - if (tmp > 7) - return 0; - if (irq_translate[tmp] == -1) - return 0; - - tmp = hw_config->dma; - if (tmp != 1 && tmp != 3) - return 0; - - if (!request_region(hw_config->io_base, 16, "soundblaster")) { - printk(KERN_ERR "AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - conf = 0x84; /* DMA and IRQ enable */ - conf |= hw_config->io_base & 0x70; /* I/O address bits */ - conf |= irq_translate[hw_config->irq]; - if (hw_config->dma == 3) - conf |= 0x08; - trix_write(0x1b, conf); - - download_boot(hw_config->io_base); - - hw_config->name = "AudioTrix SB"; - if (!sb_dsp_detect(hw_config, 0, 0, NULL)) { - release_region(hw_config->io_base, 16); - return 0; - } - - hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; - - /* Prevent false alarms */ - old_quiet = sb_be_quiet; - sb_be_quiet = 1; - - sb_dsp_init(hw_config, THIS_MODULE); - - sb_be_quiet = old_quiet; - return 1; -} - -static int __init probe_trix_mpu(struct address_info *hw_config) -{ - unsigned char conf; - static int irq_bits[] = { - -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 - }; - - if (hw_config->irq > 9) - { - printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - if (irq_bits[hw_config->irq] == -1) - { - printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x370: - conf = 0x04; - break; - case 0x3b0: - conf = 0x08; - break; - case 0x3f0: - conf = 0x0c; - break; - default: - return 0; /* Invalid port */ - } - - conf |= irq_bits[hw_config->irq] << 4; - trix_write(0x19, (trix_read(0x19) & 0x83) | conf); - hw_config->name = "AudioTrix Pro"; - return probe_uart401(hw_config, THIS_MODULE); -} - -static void __exit unload_trix_wss(struct address_info *hw_config) -{ - int dma2 = hw_config->dma2; - - if (dma2 == -1) - dma2 = hw_config->dma; - - release_region(0x390, 2); - release_region(hw_config->io_base, 4); - - ad1848_unload(hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - dma2, - 0); - sound_unload_audiodev(hw_config->slots[0]); -} - -static inline void __exit unload_trix_mpu(struct address_info *hw_config) -{ - unload_uart401(hw_config); -} - -static inline void __exit unload_trix_sb(struct address_info *hw_config) -{ - sb_dsp_unload(hw_config, mpu); -} - -static struct address_info cfg; -static struct address_info cfg2; -static struct address_info cfg_mpu; - -static int sb; -static int fw_load; - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; /* Set this for modules that need it */ -static int __initdata sb_io = -1; -static int __initdata sb_dma = -1; -static int __initdata sb_irq = -1; -static int __initdata mpu_io = -1; -static int __initdata mpu_irq = -1; - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param_hw(dma, int, dma, 0); -module_param_hw(dma2, int, dma, 0); -module_param_hw(sb_io, int, ioport, 0); -module_param_hw(sb_dma, int, dma, 0); -module_param_hw(sb_irq, int, irq, 0); -module_param_hw(mpu_io, int, ioport, 0); -module_param_hw(mpu_irq, int, irq, 0); -module_param(joystick, bool, 0); - -static int __init init_trix(void) -{ - printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - cfg2.io_base = sb_io; - cfg2.irq = sb_irq; - cfg2.dma = sb_dma; - - cfg_mpu.io_base = mpu_io; - cfg_mpu.irq = mpu_irq; - - if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { - printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); - return -EINVAL; - } - - if (cfg2.io_base != -1 && (cfg2.irq == -1 || cfg2.dma == -1)) { - printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); - return -EINVAL; - } - if (cfg_mpu.io_base != -1 && cfg_mpu.irq == -1) { - printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n"); - return -EINVAL; - } - if (!trix_boot) - { - fw_load = 1; - trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", - (char **) &trix_boot); - } - - if (!request_region(0x390, 2, "AudioTrix")) { - printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); - return -ENODEV; - } - - if (!init_trix_wss(&cfg)) { - release_region(0x390, 2); - return -ENODEV; - } - - /* - * We must attach in the right order to get the firmware - * loaded up in time. - */ - - if (cfg2.io_base != -1) { - sb = probe_trix_sb(&cfg2); - } - - if (cfg_mpu.io_base != -1) - mpu = probe_trix_mpu(&cfg_mpu); - - return 0; -} - -static void __exit cleanup_trix(void) -{ - if (fw_load) - vfree(trix_boot); - if (sb) - unload_trix_sb(&cfg2); - if (mpu) - unload_trix_mpu(&cfg_mpu); - unload_trix_wss(&cfg); -} - -module_init(init_trix); -module_exit(cleanup_trix); - -#ifndef MODULE -static int __init setup_trix (char *str) -{ - /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, mpu_io, mpu_irq */ - int ints[9]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - sb_io = ints[5]; - sb_irq = ints[6]; - sb_dma = ints[6]; - mpu_io = ints[7]; - mpu_irq = ints[8]; - - return 1; -} - -__setup("trix=", setup_trix); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h deleted file mode 100644 index 953539931237..000000000000 --- a/sound/oss/tuning.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -static unsigned short semitone_tuning[24] = -{ -/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, -/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, -/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755 -}; - -static unsigned short cent_tuning[100] = -{ -/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, -/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, -/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, -/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, -/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, -/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, -/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, -/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, -/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, -/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, -/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, -/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, -/* 96 */ 10570, 10576, 10582, 10589 -}; diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c deleted file mode 100644 index 83dcc85b8688..000000000000 --- a/sound/oss/uart401.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * sound/oss/uart401.c - * - * MPU-401 UART driver (formerly uart401_midi.c) - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * Alan Cox Reformatted, removed sound_mem usage, use normal Linux - * interrupt allocation. Protect against bogus unload - * Fixed to allow IRQ > 15 - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo got rid of check_region - * - * Status: - * Untested - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "mpu401.h" - -struct uart401_devc -{ - int base; - int irq; - int *osp; - void (*midi_input_intr) (int dev, unsigned char data); - int opened, disabled; - volatile unsigned char input_byte; - int my_dev; - int share_irq; - spinlock_t lock; -}; - -#define DATAPORT (devc->base) -#define COMDPORT (devc->base+1) -#define STATPORT (devc->base+1) - -static int uart401_status(struct uart401_devc *devc) -{ - return inb(STATPORT); -} - -#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) -#define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) - -static void uart401_cmd(struct uart401_devc *devc, unsigned char cmd) -{ - outb((cmd), COMDPORT); -} - -static int uart401_read(struct uart401_devc *devc) -{ - return inb(DATAPORT); -} - -static void uart401_write(struct uart401_devc *devc, unsigned char byte) -{ - outb((byte), DATAPORT); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static int reset_uart401(struct uart401_devc *devc); -static void enter_uart_mode(struct uart401_devc *devc); - -static void uart401_input_loop(struct uart401_devc *devc) -{ - int work_limit=30000; - - while (input_avail(devc) && --work_limit) - { - unsigned char c = uart401_read(devc); - - if (c == MPU_ACK) - devc->input_byte = c; - else if (devc->opened & OPEN_READ && devc->midi_input_intr) - devc->midi_input_intr(devc->my_dev, c); - } - if(work_limit==0) - printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base); -} - -irqreturn_t uart401intr(int irq, void *dev_id) -{ - struct uart401_devc *devc = dev_id; - - if (devc == NULL) - { - printk(KERN_ERR "uart401: bad devc\n"); - return IRQ_NONE; - } - - if (input_avail(devc)) - uart401_input_loop(devc); - return IRQ_HANDLED; -} - -static int -uart401_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - if (devc->opened) - return -EBUSY; - - /* Flush the UART */ - - while (input_avail(devc)) - uart401_read(devc); - - devc->midi_input_intr = input; - devc->opened = mode; - enter_uart_mode(devc); - devc->disabled = 0; - - return 0; -} - -static void uart401_close(int dev) -{ - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - reset_uart401(devc); - devc->opened = 0; -} - -static int uart401_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - if (devc->disabled) - return 1; - /* - * Test for input since pending input seems to block the output. - */ - - spin_lock_irqsave(&devc->lock,flags); - if (input_avail(devc)) - uart401_input_loop(devc); - - spin_unlock_irqrestore(&devc->lock,flags); - - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - if (!output_ready(devc)) - { - printk(KERN_WARNING "uart401: Timeout - Device not responding\n"); - devc->disabled = 1; - reset_uart401(devc); - enter_uart_mode(devc); - return 1; - } - uart401_write(devc, midi_byte); - return 1; -} - -static inline int uart401_start_read(int dev) -{ - return 0; -} - -static inline int uart401_end_read(int dev) -{ - return 0; -} - -static inline void uart401_kick(int dev) -{ -} - -static inline int uart401_buffer_status(int dev) -{ - return 0; -} - -#define MIDI_SYNTH_NAME "MPU-401 UART" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static const struct midi_operations uart401_operations = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = uart401_open, - .close = uart401_close, - .outputc = uart401_out, - .start_read = uart401_start_read, - .end_read = uart401_end_read, - .kick = uart401_kick, - .buffer_status = uart401_buffer_status, -}; - -static void enter_uart_mode(struct uart401_devc *devc) -{ - int ok, timeout; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - devc->input_byte = 0; - uart401_cmd(devc, UART_MODE_ON); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) - ok = 1; - else if (input_avail(devc)) - if (uart401_read(devc) == MPU_ACK) - ok = 1; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int reset_uart401(struct uart401_devc *devc) -{ - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - devc->input_byte = 0; - uart401_cmd(devc, MPU_RESET); - - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ - - for (timeout = 50000; timeout > 0 && !ok; timeout--) - { - if (devc->input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail(devc)) - { - if (uart401_read(devc) == MPU_ACK) - ok = 1; - } - } - } - - /* Flush input before enabling interrupts */ - if (ok) - uart401_input_loop(devc); - else - DDB(printk("Reset UART401 failed - No hardware detected.\n")); - - return ok; -} - -int probe_uart401(struct address_info *hw_config, struct module *owner) -{ - struct 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(struct 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), - GFP_KERNEL); - - if (!midi_devs[devc->my_dev]->converter) { - printk(KERN_WARNING "uart401: Failed to allocate memory\n"); - goto cleanup_midi_devs; - } - strcpy(midi_devs[devc->my_dev]->info.name, name); - midi_devs[devc->my_dev]->converter->id = "UART401"; - midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev; - - if (owner) - midi_devs[devc->my_dev]->converter->owner = owner; - - hw_config->slots[4] = devc->my_dev; - sequencer_init(); - devc->opened = 0; - return 1; -cleanup_midi_devs: - kfree(midi_devs[devc->my_dev]); -cleanup_unload_mididev: - sound_unload_mididev(devc->my_dev); -cleanup_irq: - if (!devc->share_irq) - free_irq(devc->irq, devc); -cleanup_devc: - kfree(devc); -cleanup_region: - release_region(hw_config->io_base, 4); - return 0; -} - -void unload_uart401(struct address_info *hw_config) -{ - struct uart401_devc *devc; - int n=hw_config->slots[4]; - - /* Not set up */ - if(n==-1 || midi_devs[n]==NULL) - return; - - /* Not allocated (erm ??) */ - - devc = midi_devs[hw_config->slots[4]]->devc; - if (devc == NULL) - return; - - reset_uart401(devc); - release_region(hw_config->io_base, 4); - - if (!devc->share_irq) - free_irq(devc->irq, devc); - kfree(midi_devs[devc->my_dev]->converter); - kfree(midi_devs[devc->my_dev]); - kfree(devc); - - /* This kills midi_devs[x] */ - sound_unload_mididev(hw_config->slots[4]); -} - -EXPORT_SYMBOL(probe_uart401); -EXPORT_SYMBOL(unload_uart401); -EXPORT_SYMBOL(uart401intr); - -static struct address_info cfg_mpu; - -static int io = -1; -static int irq = -1; - -module_param_hw(io, int, ioport, 0444); -module_param_hw(irq, int, irq, 0444); - - -static int __init init_uart401(void) -{ - cfg_mpu.irq = irq; - cfg_mpu.io_base = io; - - /* Can be loaded either for module use or to provide functions - to others */ - if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) { - printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); - if (!probe_uart401(&cfg_mpu, THIS_MODULE)) - return -ENODEV; - } - - return 0; -} - -static void __exit cleanup_uart401(void) -{ - if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) - unload_uart401(&cfg_mpu); -} - -module_init(init_uart401); -module_exit(cleanup_uart401); - -#ifndef MODULE -static int __init setup_uart401(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} - -__setup("uart401=", setup_uart401); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c deleted file mode 100644 index eda32d7eddbd..000000000000 --- a/sound/oss/uart6850.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * sound/oss/uart6850.c - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver. - * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2. - * - * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now - * uses native linux resources - * Christoph Hellwig: Adapted to module_init/module_exit - * Jeff Garzik: Made it work again, in theory - * FIXME: If the request_irq() succeeds, the probe succeeds. Ug. - * - * Status: Testing required (no shit -jgarzik) - * - * - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/spinlock.h> -/* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: - * added 6850 support, used with COVOX SoundMaster II and custom cards. - */ - -#include "sound_config.h" - -static int uart6850_base = 0x330; - -static int *uart6850_osp; - -#define DATAPORT (uart6850_base) -#define COMDPORT (uart6850_base+1) -#define STATPORT (uart6850_base+1) - -static int uart6850_status(void) -{ - return inb(STATPORT); -} - -#define input_avail() (uart6850_status()&INPUT_AVAIL) -#define output_ready() (uart6850_status()&OUTPUT_READY) - -static void uart6850_cmd(unsigned char cmd) -{ - outb(cmd, COMDPORT); -} - -static int uart6850_read(void) -{ - return inb(DATAPORT); -} - -static void uart6850_write(unsigned char byte) -{ - outb(byte, DATAPORT); -} - -#define OUTPUT_READY 0x02 /* Mask for data ready Bit */ -#define INPUT_AVAIL 0x01 /* Mask for Data Send Ready Bit */ - -#define UART_RESET 0x95 -#define UART_MODE_ON 0x03 - -static int uart6850_opened; -static int uart6850_irq; -static int uart6850_detected; -static int my_dev; -static DEFINE_SPINLOCK(lock); - -static void (*midi_input_intr) (int dev, unsigned char data); -static void poll_uart6850(unsigned long dummy); - - -static DEFINE_TIMER(uart6850_timer, poll_uart6850, 0, 0); - -static void uart6850_input_loop(void) -{ - int count = 10; - - while (count) - { - /* - * Not timed out - */ - if (input_avail()) - { - unsigned char c = uart6850_read(); - count = 100; - if (uart6850_opened & OPEN_READ) - midi_input_intr(my_dev, c); - } - else - { - while (!input_avail() && count) - count--; - } - } -} - -static irqreturn_t m6850intr(int irq, void *dev_id) -{ - if (input_avail()) - uart6850_input_loop(); - return IRQ_HANDLED; -} - -/* - * It looks like there is no input interrupts in the UART mode. Let's try - * polling. - */ - -static void poll_uart6850(unsigned long dummy) -{ - unsigned long flags; - - if (!(uart6850_opened & OPEN_READ)) - return; /* Device has been closed */ - - spin_lock_irqsave(&lock,flags); - if (input_avail()) - uart6850_input_loop(); - - uart6850_timer.expires = 1 + jiffies; - add_timer(&uart6850_timer); - - /* - * Come back later - */ - - spin_unlock_irqrestore(&lock,flags); -} - -static int uart6850_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - if (uart6850_opened) - { -/* printk("Midi6850: Midi busy\n");*/ - return -EBUSY; - } - - uart6850_cmd(UART_RESET); - uart6850_input_loop(); - midi_input_intr = input; - uart6850_opened = mode; - poll_uart6850(0); /* - * Enable input polling - */ - - return 0; -} - -static void uart6850_close(int dev) -{ - uart6850_cmd(UART_MODE_ON); - del_timer(&uart6850_timer); - uart6850_opened = 0; -} - -static int uart6850_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - - /* - * Test for input since pending input seems to block the output. - */ - - spin_lock_irqsave(&lock,flags); - - if (input_avail()) - uart6850_input_loop(); - - spin_unlock_irqrestore(&lock,flags); - - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* - * Wait - */ - if (!output_ready()) - { - printk(KERN_WARNING "Midi6850: Timeout\n"); - return 0; - } - uart6850_write(midi_byte); - return 1; -} - -static inline int uart6850_command(int dev, unsigned char *midi_byte) -{ - return 1; -} - -static inline int uart6850_start_read(int dev) -{ - return 0; -} - -static inline int uart6850_end_read(int dev) -{ - return 0; -} - -static inline void uart6850_kick(int dev) -{ -} - -static inline int uart6850_buffer_status(int dev) -{ - return 0; /* - * No data in buffers - */ -} - -#define MIDI_SYNTH_NAME "6850 UART Midi" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations uart6850_operations = -{ - .owner = THIS_MODULE, - .info = {"6850 UART", 0, 0, SNDCARD_UART6850}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = uart6850_open, - .close = uart6850_close, - .outputc = uart6850_out, - .start_read = uart6850_start_read, - .end_read = uart6850_end_read, - .kick = uart6850_kick, - .command = uart6850_command, - .buffer_status = uart6850_buffer_status -}; - - -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(); -} - -static inline int reset_uart6850(void) -{ - uart6850_read(); - return 1; /* - * OK - */ -} - -static int __init probe_uart6850(struct address_info *hw_config) -{ - int ok; - - uart6850_osp = hw_config->osp; - uart6850_base = hw_config->io_base; - uart6850_irq = hw_config->irq; - - if (request_irq(uart6850_irq, m6850intr, 0, "MIDI6850", NULL) < 0) - return 0; - - ok = reset_uart6850(); - uart6850_detected = ok; - return ok; -} - -static void __exit unload_uart6850(struct address_info *hw_config) -{ - free_irq(hw_config->irq, NULL); - sound_unload_mididev(hw_config->slots[4]); -} - -static struct address_info cfg_mpu; - -static int __initdata io = -1; -static int __initdata irq = -1; - -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); - -static int __init init_uart6850(void) -{ - cfg_mpu.io_base = io; - cfg_mpu.irq = irq; - - if (cfg_mpu.io_base == -1 || cfg_mpu.irq == -1) { - printk(KERN_INFO "uart6850: irq and io must be set.\n"); - return -EINVAL; - } - - if (probe_uart6850(&cfg_mpu)) - return -ENODEV; - attach_uart6850(&cfg_mpu); - - return 0; -} - -static void __exit cleanup_uart6850(void) -{ - unload_uart6850(&cfg_mpu); -} - -module_init(init_uart6850); -module_exit(cleanup_uart6850); - -#ifndef MODULE -static int __init setup_uart6850(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} -__setup("uart6850=", setup_uart6850); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/oss/ulaw.h b/sound/oss/ulaw.h deleted file mode 100644 index ee898a0f78ce..000000000000 --- a/sound/oss/ulaw.h +++ /dev/null @@ -1,70 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -static unsigned char ulaw_dsp[] = { - 3, 7, 11, 15, 19, 23, 27, 31, - 35, 39, 43, 47, 51, 55, 59, 63, - 66, 68, 70, 72, 74, 76, 78, 80, - 82, 84, 86, 88, 90, 92, 94, 96, - 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, - 113, 114, 114, 115, 115, 116, 116, 117, - 117, 118, 118, 119, 119, 120, 120, 121, - 121, 121, 122, 122, 122, 122, 123, 123, - 123, 123, 124, 124, 124, 124, 125, 125, - 125, 125, 125, 125, 126, 126, 126, 126, - 126, 126, 126, 126, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 253, 249, 245, 241, 237, 233, 229, 225, - 221, 217, 213, 209, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 174, 172, 170, 168, 166, 164, 162, 160, - 158, 157, 156, 155, 154, 153, 152, 151, - 150, 149, 148, 147, 146, 145, 144, 143, - 143, 142, 142, 141, 141, 140, 140, 139, - 139, 138, 138, 137, 137, 136, 136, 135, - 135, 135, 134, 134, 134, 134, 133, 133, - 133, 133, 132, 132, 132, 132, 131, 131, - 131, 131, 131, 131, 130, 130, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, -}; - -static unsigned char dsp_ulaw[] = { - 0, 0, 0, 0, 0, 1, 1, 1, - 1, 2, 2, 2, 2, 3, 3, 3, - 3, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, - 7, 8, 8, 8, 8, 9, 9, 9, - 9, 10, 10, 10, 10, 11, 11, 11, - 11, 12, 12, 12, 12, 13, 13, 13, - 13, 14, 14, 14, 14, 15, 15, 15, - 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, - 23, 24, 24, 25, 25, 26, 26, 27, - 27, 28, 28, 29, 29, 30, 30, 31, - 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 47, 49, 51, 53, 55, 57, 59, 61, - 63, 66, 70, 74, 78, 84, 92, 104, - 254, 231, 219, 211, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 175, 174, 173, 172, 171, 170, 169, 168, - 167, 166, 165, 164, 163, 162, 161, 160, - 159, 159, 158, 158, 157, 157, 156, 156, - 155, 155, 154, 154, 153, 153, 152, 152, - 151, 151, 150, 150, 149, 149, 148, 148, - 147, 147, 146, 146, 145, 145, 144, 144, - 143, 143, 143, 143, 142, 142, 142, 142, - 141, 141, 141, 141, 140, 140, 140, 140, - 139, 139, 139, 139, 138, 138, 138, 138, - 137, 137, 137, 137, 136, 136, 136, 136, - 135, 135, 135, 135, 134, 134, 134, 134, - 133, 133, 133, 133, 132, 132, 132, 132, - 131, 131, 131, 131, 130, 130, 130, 130, - 129, 129, 129, 129, 128, 128, 128, 128, -}; diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c deleted file mode 100644 index fc0ba276cc8f..000000000000 --- a/sound/oss/v_midi.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * sound/oss/v_midi.c - * - * The low level driver for the Sound Blaster DS chips. - * - * - * Copyright (C) by Hannu Savolainen 1993-1996 - * - * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * ?? - * - * Changes - * Alan Cox Modularisation, changed memory allocations - * Christoph Hellwig Adapted to module_init/module_exit - * - * Status - * Untested - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "v_midi.h" - -static vmidi_devc *v_devc[2] = { NULL, NULL}; -static int midi1,midi2; -static void *midi_mem = NULL; - -/* - * The DSP channel can be used either for input or output. Variable - * 'sb_irq_mode' will be set when the program calls read or write first time - * after open. Current version doesn't support mode changes without closing - * and reopening the device. Support for this feature may be implemented in a - * future version of this driver. - */ - - -static int v_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return -ENXIO; - - spin_lock_irqsave(&devc->lock,flags); - if (devc->opened) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -EBUSY; - } - devc->opened = 1; - spin_unlock_irqrestore(&devc->lock,flags); - - devc->intr_active = 1; - - if (mode & OPEN_READ) - { - devc->input_opened = 1; - devc->midi_input_intr = input; - } - - return 0; -} - -static void v_midi_close (int dev) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - unsigned long flags; - - if (devc == NULL) - return; - - spin_lock_irqsave(&devc->lock,flags); - devc->intr_active = 0; - devc->input_opened = 0; - devc->opened = 0; - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int v_midi_out (int dev, unsigned char midi_byte) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - vmidi_devc *pdevc; - - if (devc == NULL) - return -ENXIO; - - pdevc = midi_devs[devc->pair_mididev]->devc; - if (pdevc->input_opened > 0){ - if (MIDIbuf_avail(pdevc->my_mididev) > 500) - return 0; - pdevc->midi_input_intr (pdevc->my_mididev, midi_byte); - } - return 1; -} - -static inline int v_midi_start_read (int dev) -{ - return 0; -} - -static int v_midi_end_read (int dev) -{ - vmidi_devc *devc = midi_devs[dev]->devc; - if (devc == NULL) - return -ENXIO; - - devc->intr_active = 0; - return 0; -} - -/* why -EPERM and not -EINVAL?? */ - -static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg) -{ - return -EPERM; -} - - -#define MIDI_SYNTH_NAME "Loopback MIDI" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT - -#include "midi_synth.h" - -static struct midi_operations v_midi_operations = -{ - .owner = THIS_MODULE, - .info = {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = v_midi_open, - .close = v_midi_close, - .ioctl = v_midi_ioctl, - .outputc = v_midi_out, - .start_read = v_midi_start_read, - .end_read = v_midi_end_read, -}; - -static struct midi_operations v_midi_operations2 = -{ - .owner = THIS_MODULE, - .info = {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = v_midi_open, - .close = v_midi_close, - .ioctl = v_midi_ioctl, - .outputc = v_midi_out, - .start_read = v_midi_start_read, - .end_read = v_midi_end_read, -}; - -/* - * We kmalloc just one of these - it makes life simpler and the code - * cleaner and the memory handling far more efficient - */ - -struct vmidi_memory -{ - /* Must be first */ - struct midi_operations m_ops[2]; - struct synth_operations s_ops[2]; - struct vmidi_devc v_ops[2]; -}; - -static void __init attach_v_midi (struct address_info *hw_config) -{ - struct vmidi_memory *m; - /* printk("Attaching v_midi device.....\n"); */ - - midi1 = sound_alloc_mididev(); - if (midi1 == -1) - { - printk(KERN_ERR "v_midi: Too many midi devices detected\n"); - return; - } - - m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL); - if (m == NULL) - { - printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n"); - sound_unload_mididev(midi1); - return; - } - - midi_mem = m; - - midi_devs[midi1] = &m->m_ops[0]; - - - midi2 = sound_alloc_mididev(); - if (midi2 == -1) - { - printk (KERN_ERR "v_midi: Too many midi devices detected\n"); - kfree(m); - sound_unload_mididev(midi1); - return; - } - - midi_devs[midi2] = &m->m_ops[1]; - - /* printk("VMIDI1: %d VMIDI2: %d\n",midi1,midi2); */ - - /* for MIDI-1 */ - v_devc[0] = &m->v_ops[0]; - memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations, - sizeof (struct midi_operations)); - - v_devc[0]->my_mididev = midi1; - v_devc[0]->pair_mididev = midi2; - v_devc[0]->opened = v_devc[0]->input_opened = 0; - v_devc[0]->intr_active = 0; - v_devc[0]->midi_input_intr = NULL; - spin_lock_init(&v_devc[0]->lock); - - midi_devs[midi1]->devc = v_devc[0]; - - midi_devs[midi1]->converter = &m->s_ops[0]; - std_midi_synth.midi_dev = midi1; - memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); - midi_devs[midi1]->converter->id = "V_MIDI 1"; - - /* for MIDI-2 */ - v_devc[1] = &m->v_ops[1]; - - memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2, - sizeof (struct midi_operations)); - - v_devc[1]->my_mididev = midi2; - v_devc[1]->pair_mididev = midi1; - v_devc[1]->opened = v_devc[1]->input_opened = 0; - v_devc[1]->intr_active = 0; - v_devc[1]->midi_input_intr = NULL; - spin_lock_init(&v_devc[1]->lock); - - midi_devs[midi2]->devc = v_devc[1]; - midi_devs[midi2]->converter = &m->s_ops[1]; - - std_midi_synth.midi_dev = midi2; - memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); - midi_devs[midi2]->converter->id = "V_MIDI 2"; - - sequencer_init(); - /* printk("Attached v_midi device\n"); */ -} - -static inline int __init probe_v_midi(struct address_info *hw_config) -{ - return(1); /* always OK */ -} - - -static void __exit unload_v_midi(struct address_info *hw_config) -{ - sound_unload_mididev(midi1); - sound_unload_mididev(midi2); - kfree(midi_mem); -} - -static struct address_info cfg; /* dummy */ - -static int __init init_vmidi(void) -{ - printk("MIDI Loopback device driver\n"); - if (!probe_v_midi(&cfg)) - return -ENODEV; - attach_v_midi(&cfg); - - return 0; -} - -static void __exit cleanup_vmidi(void) -{ - unload_v_midi(&cfg); -} - -module_init(init_vmidi); -module_exit(cleanup_vmidi); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/v_midi.h b/sound/oss/v_midi.h deleted file mode 100644 index f4fc2bed07f8..000000000000 --- a/sound/oss/v_midi.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -typedef struct vmidi_devc { - int dev; - - /* State variables */ - int opened; - spinlock_t lock; - - /* MIDI fields */ - int my_mididev; - int pair_mididev; - int input_opened; - int intr_active; - void (*midi_input_intr) (int dev, unsigned char data); - } vmidi_devc; diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c deleted file mode 100644 index 92ca5bee1860..000000000000 --- a/sound/oss/vidc.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * linux/drivers/sound/vidc.c - * - * Copyright (C) 1997-2000 by Russell King <rmk@arm.linux.org.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * VIDC20 audio driver. - * - * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA - * engine. The DMA transfers fixed-format (16-bit little-endian linear) - * samples to the VIDC20, which then transfers this data serially to the - * DACs. The samplerate is controlled by the VIDC. - * - * We currently support a mixer device, but it is currently non-functional. - */ - -#include <linux/gfp.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> - -#include <mach/hardware.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/hardware/iomd.h> -#include <asm/irq.h> - -#include "sound_config.h" -#include "vidc.h" - -#ifndef _SIOC_TYPE -#define _SIOC_TYPE(x) _IOC_TYPE(x) -#endif -#ifndef _SIOC_NR -#define _SIOC_NR(x) _IOC_NR(x) -#endif - -#define VIDC_SOUND_CLOCK (250000) -#define VIDC_SOUND_CLOCK_EXT (176400) - -/* - * When using SERIAL SOUND mode (external DAC), the number of physical - * channels is fixed at 2. - */ -static int vidc_busy; -static int vidc_adev; -static int vidc_audio_rate; -static char vidc_audio_format; -static char vidc_audio_channels; - -static unsigned char vidc_level_l[SOUND_MIXER_NRDEVICES] = { - 85, /* master */ - 50, /* bass */ - 50, /* treble */ - 0, /* synth */ - 75, /* pcm */ - 0, /* speaker */ - 100, /* ext line */ - 0, /* mic */ - 100, /* CD */ - 0, -}; - -static unsigned char vidc_level_r[SOUND_MIXER_NRDEVICES] = { - 85, /* master */ - 50, /* bass */ - 50, /* treble */ - 0, /* synth */ - 75, /* pcm */ - 0, /* speaker */ - 100, /* ext line */ - 0, /* mic */ - 100, /* CD */ - 0, -}; - -static unsigned int vidc_audio_volume_l; /* left PCM vol, 0 - 65536 */ -static unsigned int vidc_audio_volume_r; /* right PCM vol, 0 - 65536 */ - -extern void vidc_update_filler(int bits, int channels); -extern int softoss_dev; - -static void -vidc_mixer_set(int mdev, unsigned int level) -{ - unsigned int lev_l = level & 0x007f; - unsigned int lev_r = (level & 0x7f00) >> 8; - unsigned int mlev_l, mlev_r; - - if (lev_l > 100) - lev_l = 100; - if (lev_r > 100) - lev_r = 100; - -#define SCALE(lev,master) ((lev) * (master) * 65536 / 10000) - - mlev_l = vidc_level_l[SOUND_MIXER_VOLUME]; - mlev_r = vidc_level_r[SOUND_MIXER_VOLUME]; - - switch (mdev) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_PCM: - vidc_level_l[mdev] = lev_l; - vidc_level_r[mdev] = lev_r; - - vidc_audio_volume_l = SCALE(lev_l, mlev_l); - vidc_audio_volume_r = SCALE(lev_r, mlev_r); -/*printk("VIDC: PCM vol %05X %05X\n", vidc_audio_volume_l, vidc_audio_volume_r);*/ - break; - } -#undef SCALE -} - -static int vidc_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) -{ - unsigned int val; - unsigned int mdev; - - if (_SIOC_TYPE(cmd) != 'M') - return -EINVAL; - - mdev = _SIOC_NR(cmd); - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - if (get_user(val, (unsigned int __user *)arg)) - return -EFAULT; - - if (mdev < SOUND_MIXER_NRDEVICES) - vidc_mixer_set(mdev, val); - else - return -EINVAL; - } - - /* - * Return parameters - */ - switch (mdev) { - case SOUND_MIXER_RECSRC: - val = 0; - break; - - case SOUND_MIXER_DEVMASK: - val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_STEREODEVS: - val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; - break; - - case SOUND_MIXER_RECMASK: - val = 0; - break; - - case SOUND_MIXER_CAPS: - val = 0; - break; - - default: - if (mdev < SOUND_MIXER_NRDEVICES) - val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8; - else - return -EINVAL; - } - - return put_user(val, (unsigned int __user *)arg) ? -EFAULT : 0; -} - -static unsigned int vidc_audio_set_format(int dev, unsigned int fmt) -{ - switch (fmt) { - default: - fmt = AFMT_S16_LE; - case AFMT_U8: - case AFMT_S8: - case AFMT_S16_LE: - vidc_audio_format = fmt; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - case AFMT_QUERY: - break; - } - return vidc_audio_format; -} - -#define my_abs(i) ((i)<0 ? -(i) : (i)) - -static int vidc_audio_set_speed(int dev, int rate) -{ - if (rate) { - unsigned int hwctrl, hwrate, hwrate_ext, rate_int, rate_ext; - unsigned int diff_int, diff_ext; - unsigned int newsize, new2size; - - hwctrl = 0x00000003; - - /* Using internal clock */ - hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; - if (hwrate < 3) - hwrate = 3; - if (hwrate > 255) - hwrate = 255; - - /* Using exernal clock */ - hwrate_ext = (((VIDC_SOUND_CLOCK_EXT * 2) / rate) + 1) >> 1; - if (hwrate_ext < 3) - hwrate_ext = 3; - if (hwrate_ext > 255) - hwrate_ext = 255; - - rate_int = VIDC_SOUND_CLOCK / hwrate; - rate_ext = VIDC_SOUND_CLOCK_EXT / hwrate_ext; - - /* Chose between external and internal clock */ - diff_int = my_abs(rate_ext-rate); - diff_ext = my_abs(rate_int-rate); - if (diff_ext < diff_int) { - /*printk("VIDC: external %d %d %d\n", rate, rate_ext, hwrate_ext);*/ - hwrate=hwrate_ext; - hwctrl=0x00000002; - /* Allow roughly 0.4% tolerance */ - if (diff_ext > (rate/256)) - rate=rate_ext; - } else { - /*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/ - hwctrl=0x00000003; - /* Allow roughly 0.4% tolerance */ - if (diff_int > (rate/256)) - rate=rate_int; - } - - vidc_writel(0xb0000000 | (hwrate - 2)); - vidc_writel(0xb1000000 | hwctrl); - - newsize = (10000 / hwrate) & ~3; - if (newsize < 208) - newsize = 208; - if (newsize > 4096) - newsize = 4096; - for (new2size = 128; new2size < newsize; new2size <<= 1); - if (new2size - newsize > newsize - (new2size >> 1)) - new2size >>= 1; - if (new2size > 4096) { - printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n", - newsize, new2size); - new2size = 4096; - } - /*printk("VIDC: dma size %d\n", new2size);*/ - dma_bufsize = new2size; - vidc_audio_rate = rate; - } - return vidc_audio_rate; -} - -static short vidc_audio_set_channels(int dev, short channels) -{ - switch (channels) { - default: - channels = 2; - case 1: - case 2: - vidc_audio_channels = channels; - vidc_update_filler(vidc_audio_format, vidc_audio_channels); - case 0: - break; - } - return vidc_audio_channels; -} - -/* - * Open the device - */ -static int vidc_audio_open(int dev, int mode) -{ - /* This audio device does not have recording capability */ - if (mode == OPEN_READ) - return -EPERM; - - if (vidc_busy) - return -EBUSY; - - vidc_busy = 1; - return 0; -} - -/* - * Close the device - */ -static void vidc_audio_close(int dev) -{ - vidc_busy = 0; -} - -/* - * Output a block via DMA to sound device. - * - * We just set the DMA start and count; the DMA interrupt routine - * will take care of formatting the samples (via the appropriate - * vidc_filler routine), and flag via vidc_audio_dma_interrupt when - * more data is required. - */ -static void -vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - - local_irq_save(flags); - dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; - dma_count = total_count; - local_irq_restore(flags); -} - -static void -vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag) -{ -} - -static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) -{ - return -EINVAL; -} - -static irqreturn_t vidc_audio_dma_interrupt(void) -{ - DMAbuf_outputintr(vidc_adev, 1); - return IRQ_HANDLED; -} - -/* - * Prepare for outputting samples. - * - * Each buffer that will be passed will be `bsize' bytes long, - * with a total of `bcount' buffers. - */ -static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) -{ - struct audio_operations *adev = audio_devs[dev]; - - dma_interrupt = NULL; - adev->dmap_out->flags |= DMA_NODMA; - - return 0; -} - -/* - * Stop our current operation. - */ -static void vidc_audio_reset(int dev) -{ - dma_interrupt = NULL; -} - -static int vidc_audio_local_qlen(int dev) -{ - return /*dma_count !=*/ 0; -} - -static void vidc_audio_trigger(int dev, int enable_bits) -{ - struct audio_operations *adev = audio_devs[dev]; - - if (enable_bits & PCM_ENABLE_OUTPUT) { - if (!(adev->dmap_out->flags & DMA_ACTIVE)) { - unsigned long flags; - - local_irq_save(flags); - - /* prevent recusion */ - adev->dmap_out->flags |= DMA_ACTIVE; - - dma_interrupt = vidc_audio_dma_interrupt; - vidc_sound_dma_irq(0, NULL); - iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR); - - local_irq_restore(flags); - } - } -} - -static struct audio_driver vidc_audio_driver = -{ - .owner = THIS_MODULE, - .open = vidc_audio_open, - .close = vidc_audio_close, - .output_block = vidc_audio_output_block, - .start_input = vidc_audio_start_input, - .prepare_for_input = vidc_audio_prepare_for_input, - .prepare_for_output = vidc_audio_prepare_for_output, - .halt_io = vidc_audio_reset, - .local_qlen = vidc_audio_local_qlen, - .trigger = vidc_audio_trigger, - .set_speed = vidc_audio_set_speed, - .set_bits = vidc_audio_set_format, - .set_channels = vidc_audio_set_channels -}; - -static struct mixer_operations vidc_mixer_operations = { - .owner = THIS_MODULE, - .id = "VIDC", - .name = "VIDCsound", - .ioctl = vidc_mixer_ioctl -}; - -void vidc_update_filler(int format, int channels) -{ -#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) - - switch (TYPE(format, channels)) { - default: - case TYPE(AFMT_U8, 1): - vidc_filler = vidc_fill_1x8_u; - break; - - case TYPE(AFMT_U8, 2): - vidc_filler = vidc_fill_2x8_u; - break; - - case TYPE(AFMT_S8, 1): - vidc_filler = vidc_fill_1x8_s; - break; - - case TYPE(AFMT_S8, 2): - vidc_filler = vidc_fill_2x8_s; - break; - - case TYPE(AFMT_S16_LE, 1): - vidc_filler = vidc_fill_1x16_s; - break; - - case TYPE(AFMT_S16_LE, 2): - vidc_filler = vidc_fill_2x16_s; - break; - } -} - -static void __init attach_vidc(struct address_info *hw_config) -{ - char name[32]; - int i, adev; - - sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype); - conf_printf(name, hw_config); - memset(dma_buf, 0, sizeof(dma_buf)); - - adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name, - &vidc_audio_driver, sizeof(vidc_audio_driver), - DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, - NULL, hw_config->dma, hw_config->dma2); - - if (adev < 0) - goto audio_failed; - - /* - * 1024 bytes => 64 buffers - */ - audio_devs[adev]->min_fragment = 10; - audio_devs[adev]->mixer_dev = num_mixers; - - audio_devs[adev]->mixer_dev = - sound_install_mixer(MIXER_DRIVER_VERSION, - name, &vidc_mixer_operations, - sizeof(vidc_mixer_operations), NULL); - - if (audio_devs[adev]->mixer_dev < 0) - goto mixer_failed; - - for (i = 0; i < 2; i++) { - dma_buf[i] = get_zeroed_page(GFP_KERNEL); - if (!dma_buf[i]) { - printk(KERN_ERR "%s: can't allocate required buffers\n", - name); - goto mem_failed; - } - dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]); - } - - if (sound_alloc_dma(hw_config->dma, hw_config->name)) { - printk(KERN_ERR "%s: DMA %d is in use\n", name, hw_config->dma); - goto dma_failed; - } - - if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, - hw_config->name, &dma_start)) { - printk(KERN_ERR "%s: IRQ %d is in use\n", name, hw_config->irq); - goto irq_failed; - } - vidc_adev = adev; - vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); - - return; - -irq_failed: - sound_free_dma(hw_config->dma); -dma_failed: -mem_failed: - for (i = 0; i < 2; i++) - free_page(dma_buf[i]); - sound_unload_mixerdev(audio_devs[adev]->mixer_dev); -mixer_failed: - sound_unload_audiodev(adev); -audio_failed: - return; -} - -static int __init probe_vidc(struct address_info *hw_config) -{ - hw_config->irq = IRQ_DMAS0; - hw_config->dma = DMA_VIRTUAL_SOUND; - hw_config->dma2 = -1; - hw_config->card_subtype = 16; - hw_config->name = "VIDC20"; - return 1; -} - -static void __exit unload_vidc(struct address_info *hw_config) -{ - int i, adev = vidc_adev; - - vidc_adev = -1; - - free_irq(hw_config->irq, &dma_start); - sound_free_dma(hw_config->dma); - - if (adev >= 0) { - sound_unload_mixerdev(audio_devs[adev]->mixer_dev); - sound_unload_audiodev(adev); - for (i = 0; i < 2; i++) - free_page(dma_buf[i]); - } -} - -static struct address_info cfg; - -static int __init init_vidc(void) -{ - if (probe_vidc(&cfg) == 0) - return -ENODEV; - - attach_vidc(&cfg); - - return 0; -} - -static void __exit cleanup_vidc(void) -{ - unload_vidc(&cfg); -} - -module_init(init_vidc); -module_exit(cleanup_vidc); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("VIDC20 audio driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h deleted file mode 100644 index 0d1424751ecd..000000000000 --- a/sound/oss/vidc.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/drivers/sound/vidc.h - * - * Copyright (C) 1997 Russell King <rmk@arm.linux.org.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * VIDC sound function prototypes - */ - -/* vidc_fill.S */ - -/* - * Filler routines for different channels and sample sizes - */ - -extern unsigned long vidc_fill_1x8_u(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x8_u(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_1x8_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x8_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_1x16_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x16_s(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); - -/* - * DMA Interrupt handler - */ - -extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref); - -/* - * Filler routine pointer - */ - -extern unsigned long (*vidc_filler) (unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); - -/* - * Virtual DMA buffer exhausted - */ - -extern irqreturn_t (*dma_interrupt) (void); - -/* - * Virtual DMA buffer addresses - */ - -extern unsigned long dma_start, dma_count, dma_bufsize; -extern unsigned long dma_buf[2], dma_pbuf[2]; - -/* vidc_synth.c */ - -extern void vidc_synth_init(struct address_info *hw_config); -extern void vidc_synth_exit(struct address_info *hw_config); -extern int vidc_synth_get_volume(void); -extern int vidc_synth_set_volume(int vol); diff --git a/sound/oss/vidc_fill.S b/sound/oss/vidc_fill.S deleted file mode 100644 index bed34921d176..000000000000 --- a/sound/oss/vidc_fill.S +++ /dev/null @@ -1,218 +0,0 @@ -/* - * linux/drivers/sound/vidc_fill.S - * - * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Filler routines for DMA buffers - */ -#include <linux/linkage.h> -#include <asm/assembler.h> -#include <mach/hardware.h> -#include <asm/hardware/iomd.h> - - .text - -ENTRY(vidc_fill_1x8_u) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldrb r4, [r0], #1 - eor r4, r4, #0x80 - and r4, ip, r4, lsl #8 - orr r4, r4, r4, lsl #16 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_2x8_u) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldr r4, [r0], #2 - and r5, r4, ip - and r4, ip, r4, lsl #8 - orr r4, r4, r5, lsl #16 - orr r4, r4, r4, lsr #8 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_1x8_s) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldrb r4, [r0], #1 - and r4, ip, r4, lsl #8 - orr r4, r4, r4, lsl #16 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_2x8_s) - mov ip, #0xff00 -1: cmp r0, r1 - bge vidc_clear - ldr r4, [r0], #2 - and r5, r4, ip - and r4, ip, r4, lsl #8 - orr r4, r4, r5, lsl #16 - orr r4, r4, r4, lsr #8 - str r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_1x16_s) - mov ip, #0xff00 - orr ip, ip, ip, lsr #8 -1: cmp r0, r1 - bge vidc_clear - ldr r5, [r0], #2 - and r4, r5, ip - orr r4, r4, r4, lsl #16 - str r4, [r2], #4 - cmp r0, r1 - addlt r0, r0, #2 - andlt r4, r5, ip, lsl #16 - orrlt r4, r4, r4, lsr #16 - strlt r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_2x16_s) - mov ip, #0xff00 - orr ip, ip, ip, lsr #8 -1: cmp r0, r1 - bge vidc_clear - ldr r4, [r0], #4 - str r4, [r2], #4 - cmp r0, r1 - ldrlt r4, [r0], #4 - strlt r4, [r2], #4 - cmp r2, r3 - blt 1b - mov pc, lr - -ENTRY(vidc_fill_noaudio) - mov r0, #0 - mov r1, #0 -2: mov r4, #0 - mov r5, #0 -1: cmp r2, r3 - stmltia r2!, {r0, r1, r4, r5} - blt 1b - mov pc, lr - -ENTRY(vidc_clear) - mov r0, #0 - mov r1, #0 - tst r2, #4 - str r0, [r2], #4 - tst r2, #8 - stmia r2!, {r0, r1} - b 2b - -/* - * Call filler routines with: - * r0 = phys address - * r1 = phys end - * r2 = buffer - * Returns: - * r0 = new buffer address - * r2 = new buffer finish - * r4 = corrupted - * r5 = corrupted - * ip = corrupted - */ - -ENTRY(vidc_sound_dma_irq) - stmfd sp!, {r4 - r8, lr} - ldr r8, =dma_start - ldmia r8, {r0, r1, r2, r3, r4, r5} - teq r1, #0 - adreq r4, vidc_fill_noaudio - moveq r7, #1 << 31 - movne r7, #0 - mov ip, #IOMD_BASE & 0xff000000 - orr ip, ip, #IOMD_BASE & 0x00ff0000 - ldrb r6, [ip, #IOMD_SD0ST] - tst r6, #DMA_ST_OFL @ Check for overrun - eorne r6, r6, #DMA_ST_AB - tst r6, #DMA_ST_AB - moveq r2, r3 @ DMAing A, update B - add r3, r2, r5 @ End of DMA buffer - add r1, r1, r0 @ End of virtual DMA buffer - mov lr, pc - mov pc, r4 @ Call fill routine (uses r4, ip) - sub r1, r1, r0 @ Remaining length - stmia r8, {r0, r1} - mov r0, #0 - tst r2, #4 @ Round buffer up to 4 words - strne r0, [r2], #4 - tst r2, #8 - strne r0, [r2], #4 - strne r0, [r2], #4 - sub r2, r2, #16 - mov r2, r2, lsl #20 - movs r2, r2, lsr #20 - orreq r2, r2, #1 << 30 @ Set L bit - orr r2, r2, r7 - ldmdb r8, {r3, r4, r5} - tst r6, #DMA_ST_AB - mov ip, #IOMD_BASE & 0xff000000 - orr ip, ip, #IOMD_BASE & 0x00ff0000 - streq r4, [ip, #IOMD_SD0CURB] - strne r5, [ip, #IOMD_SD0CURA] - streq r2, [ip, #IOMD_SD0ENDB] - strne r2, [ip, #IOMD_SD0ENDA] - ldr lr, [ip, #IOMD_SD0ST] - tst lr, #DMA_ST_OFL - bne 1f - tst r6, #DMA_ST_AB - strne r4, [ip, #IOMD_SD0CURB] - streq r5, [ip, #IOMD_SD0CURA] - strne r2, [ip, #IOMD_SD0ENDB] - streq r2, [ip, #IOMD_SD0ENDA] -1: teq r7, #0 - mov r0, #0x10 - strneb r0, [ip, #IOMD_SD0CR] - ldmfd sp!, {r4 - r8, lr} - mov r0, #1 @ IRQ_HANDLED - teq r1, #0 @ If we have no more - movne pc, lr - teq r3, #0 - movne pc, r3 @ Call interrupt routine - mov pc, lr - - .data - .globl dma_interrupt -dma_interrupt: - .long 0 @ r3 - .globl dma_pbuf -dma_pbuf: - .long 0 @ r4 - .long 0 @ r5 - .globl dma_start -dma_start: - .long 0 @ r0 - .globl dma_count -dma_count: - .long 0 @ r1 - .globl dma_buf -dma_buf: - .long 0 @ r2 - .long 0 @ r3 - .globl vidc_filler -vidc_filler: - .long vidc_fill_noaudio @ r4 - .globl dma_bufsize -dma_bufsize: - .long 0x1000 @ r5 diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c deleted file mode 100644 index 4f0c3a232e41..000000000000 --- a/sound/oss/waveartist.c +++ /dev/null @@ -1,2043 +0,0 @@ -/* - * linux/sound/oss/waveartist.c - * - * The low level driver for the RWA010 Rockwell Wave Artist - * codec chip used in the Rebel.com NetWinder. - * - * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) - * and Pat Beirne (patb@corel.ca) - * - * - * Copyright (C) by Rebel.com 1998-1999 - * - * RWA010 specs received under NDA from Rockwell - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> - * Added __init to waveartist_init() - */ - -/* Debugging */ -#define DEBUG_CMD 1 -#define DEBUG_OUT 2 -#define DEBUG_IN 4 -#define DEBUG_INTR 8 -#define DEBUG_MIXER 16 -#define DEBUG_TRIGGER 32 - -#define debug_flg (0) - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/bitops.h> - - -#include "sound_config.h" -#include "waveartist.h" - -#ifdef CONFIG_ARM -#include <mach/hardware.h> -#include <asm/mach-types.h> -#endif - -#ifndef NO_DMA -#define NO_DMA 255 -#endif - -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH |\ - SOUND_MASK_PCM |\ - SOUND_MASK_LINE |\ - SOUND_MASK_MIC |\ - SOUND_MASK_LINE1 |\ - SOUND_MASK_RECLEV |\ - SOUND_MASK_VOLUME |\ - SOUND_MASK_IMIX) - -static unsigned short levels[SOUND_MIXER_NRDEVICES] = { - 0x5555, /* Master Volume */ - 0x0000, /* Bass */ - 0x0000, /* Treble */ - 0x2323, /* Synth (FM) */ - 0x4b4b, /* PCM */ - 0x6464, /* PC Speaker */ - 0x0000, /* Ext Line */ - 0x0000, /* Mic */ - 0x0000, /* CD */ - 0x6464, /* Recording monitor */ - 0x0000, /* SB PCM (ALT PCM) */ - 0x0000, /* Recording level */ - 0x6464, /* Input gain */ - 0x6464, /* Output gain */ - 0x0000, /* Line1 (Aux1) */ - 0x0000, /* Line2 (Aux2) */ - 0x0000, /* Line3 (Aux3) */ - 0x0000, /* Digital1 */ - 0x0000, /* Digital2 */ - 0x0000, /* Digital3 */ - 0x0000, /* Phone In */ - 0x6464, /* Phone Out */ - 0x0000, /* Video */ - 0x0000, /* Radio */ - 0x0000 /* Monitor */ -}; - -struct wavnc_info { - struct address_info hw; /* hardware */ - char *chip_name; - - int xfer_count; - int audio_mode; - int open_mode; - int audio_flags; - int record_dev; - int playback_dev; - int dev_no; - - /* Mixer parameters */ - const struct waveartist_mixer_info *mix; - - unsigned short *levels; /* cache of volume settings */ - int recmask; /* currently enabled recording device! */ - -#ifdef CONFIG_ARCH_NETWINDER - signed int slider_vol; /* hardware slider volume */ - unsigned int handset_detect :1; - unsigned int telephone_detect:1; - unsigned int no_autoselect :1;/* handset/telephone autoselects a path */ - unsigned int spkr_mute_state :1;/* set by ioctl or autoselect */ - unsigned int line_mute_state :1;/* set by ioctl or autoselect */ - unsigned int use_slider :1;/* use slider setting for o/p vol */ -#endif -}; - -/* - * This is the implementation specific mixer information. - */ -struct waveartist_mixer_info { - unsigned int supported_devs; /* Supported devices */ - unsigned int recording_devs; /* Recordable devies */ - unsigned int stereo_devs; /* Stereo devices */ - - unsigned int (*select_input)(struct wavnc_info *, unsigned int, - unsigned char *, unsigned char *); - int (*decode_mixer)(struct wavnc_info *, int, - unsigned char, unsigned char); - int (*get_mixer)(struct wavnc_info *, int); -}; - -struct wavnc_port_info { - int open_mode; - int speed; - int channels; - int audio_format; -}; - -static int nr_waveartist_devs; -static struct wavnc_info adev_info[MAX_AUDIO_DEV]; -static DEFINE_SPINLOCK(waveartist_lock); - -#ifndef CONFIG_ARCH_NETWINDER -#define machine_is_netwinder() 0 -#else -static struct timer_list vnc_timer; -static void vnc_configure_mixer(struct wavnc_info *devc, - unsigned int input_mask); -static int vnc_private_ioctl(int dev, unsigned int cmd, int __user *arg); -static void vnc_slider_tick(unsigned long data); -#endif - -static inline void -waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set) -{ - unsigned int ctlr_port = hw->io_base + CTLR; - - clear = ~clear & inb(ctlr_port); - - outb(clear | set, ctlr_port); -} - -/* Toggle IRQ acknowledge line - */ -static inline void -waveartist_iack(struct wavnc_info *devc) -{ - unsigned int ctlr_port = devc->hw.io_base + CTLR; - int old_ctlr; - - old_ctlr = inb(ctlr_port) & ~IRQ_ACK; - - outb(old_ctlr | IRQ_ACK, ctlr_port); - outb(old_ctlr, ctlr_port); -} - -static inline int -waveartist_sleep(int timeout_ms) -{ - unsigned int timeout = msecs_to_jiffies(timeout_ms*100); - return schedule_timeout_interruptible(timeout); -} - -static int -waveartist_reset(struct wavnc_info *devc) -{ - struct address_info *hw = &devc->hw; - unsigned int timeout, res = -1; - - waveartist_set_ctlr(hw, -1, RESET); - waveartist_sleep(2); - waveartist_set_ctlr(hw, RESET, 0); - - timeout = 500; - do { - mdelay(2); - - if (inb(hw->io_base + STATR) & CMD_RF) { - res = inw(hw->io_base + CMDR); - if (res == 0x55aa) - break; - } - } while (--timeout); - - if (timeout == 0) { - printk(KERN_WARNING "WaveArtist: reset timeout "); - if (res != (unsigned int)-1) - printk("(res=%04X)", res); - printk("\n"); - return 1; - } - return 0; -} - -/* Helper function to send and receive words - * from WaveArtist. It handles all the handshaking - * and can send or receive multiple words. - */ -static int -waveartist_cmd(struct wavnc_info *devc, - int nr_cmd, unsigned int *cmd, - int nr_resp, unsigned int *resp) -{ - unsigned int io_base = devc->hw.io_base; - unsigned int timed_out = 0; - unsigned int i; - - if (debug_flg & DEBUG_CMD) { - printk("waveartist_cmd: cmd="); - - for (i = 0; i < nr_cmd; i++) - printk("%04X ", cmd[i]); - - printk("\n"); - } - - if (inb(io_base + STATR) & CMD_RF) { - int old_data; - - /* flush the port - */ - - old_data = inw(io_base + CMDR); - - if (debug_flg & DEBUG_CMD) - printk("flushed %04X...", old_data); - - udelay(10); - } - - for (i = 0; !timed_out && i < nr_cmd; i++) { - int count; - - for (count = 5000; count; count--) - if (inb(io_base + STATR) & CMD_WE) - break; - - if (!count) - timed_out = 1; - else - outw(cmd[i], io_base + CMDR); - } - - for (i = 0; !timed_out && i < nr_resp; i++) { - int count; - - for (count = 5000; count; count--) - if (inb(io_base + STATR) & CMD_RF) - break; - - if (!count) - timed_out = 1; - else - resp[i] = inw(io_base + CMDR); - } - - if (debug_flg & DEBUG_CMD) { - if (!timed_out) { - printk("waveartist_cmd: resp="); - - for (i = 0; i < nr_resp; i++) - printk("%04X ", resp[i]); - - printk("\n"); - } else - printk("waveartist_cmd: timed out\n"); - } - - return timed_out ? 1 : 0; -} - -/* - * Send one command word - */ -static inline int -waveartist_cmd1(struct wavnc_info *devc, unsigned int cmd) -{ - return waveartist_cmd(devc, 1, &cmd, 0, NULL); -} - -/* - * Send one command, receive one word - */ -static inline unsigned int -waveartist_cmd1_r(struct wavnc_info *devc, unsigned int cmd) -{ - unsigned int ret; - - waveartist_cmd(devc, 1, &cmd, 1, &ret); - - return ret; -} - -/* - * Send a double command, receive one - * word (and throw it away) - */ -static inline int -waveartist_cmd2(struct wavnc_info *devc, unsigned int cmd, unsigned int arg) -{ - unsigned int vals[2]; - - vals[0] = cmd; - vals[1] = arg; - - return waveartist_cmd(devc, 2, vals, 1, vals); -} - -/* - * Send a triple command - */ -static inline int -waveartist_cmd3(struct wavnc_info *devc, unsigned int cmd, - unsigned int arg1, unsigned int arg2) -{ - unsigned int vals[3]; - - vals[0] = cmd; - vals[1] = arg1; - vals[2] = arg2; - - return waveartist_cmd(devc, 3, vals, 0, NULL); -} - -static int -waveartist_getrev(struct wavnc_info *devc, char *rev) -{ - unsigned int temp[2]; - unsigned int cmd = WACMD_GETREV; - - waveartist_cmd(devc, 1, &cmd, 2, temp); - - rev[0] = temp[0] >> 8; - rev[1] = temp[0] & 255; - rev[2] = '\0'; - - return temp[0]; -} - -static void waveartist_halt_output(int dev); -static void waveartist_halt_input(int dev); -static void waveartist_halt(int dev); -static void waveartist_trigger(int dev, int state); - -static int -waveartist_open(int dev, int mode) -{ - struct wavnc_info *devc; - struct wavnc_port_info *portc; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (struct wavnc_info *) audio_devs[dev]->devc; - portc = (struct wavnc_port_info *) audio_devs[dev]->portc; - - spin_lock_irqsave(&waveartist_lock, flags); - if (portc->open_mode || (devc->open_mode & mode)) { - spin_unlock_irqrestore(&waveartist_lock, flags); - return -EBUSY; - } - - devc->audio_mode = 0; - devc->open_mode |= mode; - portc->open_mode = mode; - waveartist_trigger(dev, 0); - - if (mode & OPEN_READ) - devc->record_dev = dev; - if (mode & OPEN_WRITE) - devc->playback_dev = dev; - spin_unlock_irqrestore(&waveartist_lock, flags); - - return 0; -} - -static void -waveartist_close(int dev) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned long flags; - - spin_lock_irqsave(&waveartist_lock, flags); - - waveartist_halt(dev); - - devc->audio_mode = 0; - devc->open_mode &= ~portc->open_mode; - portc->open_mode = 0; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - unsigned int count = __count; - - if (debug_flg & DEBUG_OUT) - printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", - buf, count); - /* - * 16 bit data - */ - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) - count >>= 1; - - if (portc->channels > 1) - count >>= 1; - - count -= 1; - - if (devc->audio_mode & PCM_ENABLE_OUTPUT && - audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - count == devc->xfer_count) { - devc->audio_mode |= PCM_ENABLE_OUTPUT; - return; /* - * Auto DMA mode on. No need to react - */ - } - - spin_lock_irqsave(&waveartist_lock, flags); - - /* - * set sample count - */ - waveartist_cmd2(devc, WACMD_OUTPUTSIZE, count); - - devc->xfer_count = count; - devc->audio_mode |= PCM_ENABLE_OUTPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - unsigned int count = __count; - - if (debug_flg & DEBUG_IN) - printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", - buf, count); - - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - count >>= 1; - - if (portc->channels > 1) - count >>= 1; - - count -= 1; - - if (devc->audio_mode & PCM_ENABLE_INPUT && - audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - count == devc->xfer_count) { - devc->audio_mode |= PCM_ENABLE_INPUT; - return; /* - * Auto DMA mode on. No need to react - */ - } - - spin_lock_irqsave(&waveartist_lock, flags); - - /* - * set sample count - */ - waveartist_cmd2(devc, WACMD_INPUTSIZE, count); - - devc->xfer_count = count; - devc->audio_mode |= PCM_ENABLE_INPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static int -waveartist_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - return -EINVAL; -} - -static unsigned int -waveartist_get_speed(struct wavnc_port_info *portc) -{ - unsigned int speed; - - /* - * program the speed, channels, bits - */ - if (portc->speed == 8000) - speed = 0x2E71; - else if (portc->speed == 11025) - speed = 0x4000; - else if (portc->speed == 22050) - speed = 0x8000; - else if (portc->speed == 44100) - speed = 0x0; - else { - /* - * non-standard - just calculate - */ - speed = portc->speed << 16; - - speed = (speed / 44100) & 65535; - } - - return speed; -} - -static unsigned int -waveartist_get_bits(struct wavnc_port_info *portc) -{ - unsigned int bits; - - if (portc->audio_format == AFMT_S16_LE) - bits = 1; - else if (portc->audio_format == AFMT_S8) - bits = 0; - else - bits = 2; //default AFMT_U8 - - return bits; -} - -static int -waveartist_prepare_for_input(int dev, int bsize, int bcount) -{ - unsigned long flags; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned int speed, bits; - - if (devc->audio_mode) - return 0; - - speed = waveartist_get_speed(portc); - bits = waveartist_get_bits(portc); - - spin_lock_irqsave(&waveartist_lock, flags); - - if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk(KERN_WARNING "waveartist: error setting the " - "record format to %d\n", portc->audio_format); - - if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk(KERN_WARNING "waveartist: error setting record " - "to %d channels\n", portc->channels); - - /* - * write cmd SetSampleSpeedTimeConstant - */ - if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk(KERN_WARNING "waveartist: error setting the record " - "speed to %dHz.\n", portc->speed); - - if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk(KERN_WARNING "waveartist: error setting the record " - "data path to 0x%X\n", 1); - - if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk(KERN_WARNING "waveartist: error setting the record " - "format to %d\n", portc->audio_format); - - devc->xfer_count = 0; - spin_unlock_irqrestore(&waveartist_lock, flags); - waveartist_halt_input(dev); - - if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n", - inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n", - inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n", - inb(devc->hw.io_base + IRQSTAT)); - } - - return 0; -} - -static int -waveartist_prepare_for_output(int dev, int bsize, int bcount) -{ - unsigned long flags; - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned int speed, bits; - - /* - * program the speed, channels, bits - */ - speed = waveartist_get_speed(portc); - bits = waveartist_get_bits(portc); - - spin_lock_irqsave(&waveartist_lock, flags); - - if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && - waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk(KERN_WARNING "waveartist: error setting the playback " - "speed to %dHz.\n", portc->speed); - - if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk(KERN_WARNING "waveartist: error setting the playback " - "to %d channels\n", portc->channels); - - if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk(KERN_WARNING "waveartist: error setting the playback " - "data path to 0x%X\n", 0); - - if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk(KERN_WARNING "waveartist: error setting the playback " - "format to %d\n", portc->audio_format); - - devc->xfer_count = 0; - spin_unlock_irqrestore(&waveartist_lock, flags); - waveartist_halt_output(dev); - - if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); - } - - return 0; -} - -static void -waveartist_halt(int dev) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - struct wavnc_info *devc; - - if (portc->open_mode & OPEN_WRITE) - waveartist_halt_output(dev); - - if (portc->open_mode & OPEN_READ) - waveartist_halt_input(dev); - - devc = (struct wavnc_info *) audio_devs[dev]->devc; - devc->audio_mode = 0; -} - -static void -waveartist_halt_input(int dev) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&waveartist_lock, flags); - - /* - * Stop capture - */ - waveartist_cmd1(devc, WACMD_INPUTSTOP); - - devc->audio_mode &= ~PCM_ENABLE_INPUT; - - /* - * Clear interrupt by toggling - * the IRQ_ACK bit in CTRL - */ - if (inb(devc->hw.io_base + STATR) & IRQ_REQ) - waveartist_iack(devc); - -// devc->audio_mode &= ~PCM_ENABLE_INPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_halt_output(int dev) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - unsigned long flags; - - spin_lock_irqsave(&waveartist_lock, flags); - - waveartist_cmd1(devc, WACMD_OUTPUTSTOP); - - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - - /* - * Clear interrupt by toggling - * the IRQ_ACK bit in CTRL - */ - if (inb(devc->hw.io_base + STATR) & IRQ_REQ) - waveartist_iack(devc); - -// devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static void -waveartist_trigger(int dev, int state) -{ - struct wavnc_info *devc = (struct wavnc_info *) - audio_devs[dev]->devc; - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - unsigned long flags; - - if (debug_flg & DEBUG_TRIGGER) { - printk("wavnc: audio trigger "); - if (state & PCM_ENABLE_INPUT) - printk("in "); - if (state & PCM_ENABLE_OUTPUT) - printk("out"); - printk("\n"); - } - - spin_lock_irqsave(&waveartist_lock, flags); - - state &= devc->audio_mode; - - if (portc->open_mode & OPEN_READ && - state & PCM_ENABLE_INPUT) - /* - * enable ADC Data Transfer to PC - */ - waveartist_cmd1(devc, WACMD_INPUTSTART); - - if (portc->open_mode & OPEN_WRITE && - state & PCM_ENABLE_OUTPUT) - /* - * enable DAC data transfer from PC - */ - waveartist_cmd1(devc, WACMD_OUTPUTSTART); - - spin_unlock_irqrestore(&waveartist_lock, flags); -} - -static int -waveartist_set_speed(int dev, int arg) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - - if (arg <= 0) - return portc->speed; - - if (arg < 5000) - arg = 5000; - if (arg > 44100) - arg = 44100; - - portc->speed = arg; - return portc->speed; - -} - -static short -waveartist_set_channels(int dev, short arg) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - - if (arg != 1 && arg != 2) - return portc->channels; - - portc->channels = arg; - return arg; -} - -static unsigned int -waveartist_set_bits(int dev, unsigned int arg) -{ - struct wavnc_port_info *portc = (struct wavnc_port_info *) - audio_devs[dev]->portc; - - if (arg == 0) - return portc->audio_format; - - if ((arg != AFMT_U8) && (arg != AFMT_S16_LE) && (arg != AFMT_S8)) - arg = AFMT_U8; - - portc->audio_format = arg; - - return arg; -} - -static struct audio_driver waveartist_audio_driver = { - .owner = THIS_MODULE, - .open = waveartist_open, - .close = waveartist_close, - .output_block = waveartist_output_block, - .start_input = waveartist_start_input, - .ioctl = waveartist_ioctl, - .prepare_for_input = waveartist_prepare_for_input, - .prepare_for_output = waveartist_prepare_for_output, - .halt_io = waveartist_halt, - .halt_input = waveartist_halt_input, - .halt_output = waveartist_halt_output, - .trigger = waveartist_trigger, - .set_speed = waveartist_set_speed, - .set_bits = waveartist_set_bits, - .set_channels = waveartist_set_channels -}; - - -static irqreturn_t -waveartist_intr(int irq, void *dev_id) -{ - struct wavnc_info *devc = dev_id; - int irqstatus, status; - - spin_lock(&waveartist_lock); - irqstatus = inb(devc->hw.io_base + IRQSTAT); - status = inb(devc->hw.io_base + STATR); - - if (debug_flg & DEBUG_INTR) - printk("waveartist_intr: stat=%02x, irqstat=%02x\n", - status, irqstatus); - - if (status & IRQ_REQ) /* Clear interrupt */ - waveartist_iack(devc); - else - printk(KERN_WARNING "waveartist: unexpected interrupt\n"); - - if (irqstatus & 0x01) { - int temp = 1; - - /* PCM buffer done - */ - if ((status & DMA0) && (devc->audio_mode & PCM_ENABLE_OUTPUT)) { - DMAbuf_outputintr(devc->playback_dev, 1); - temp = 0; - } - if ((status & DMA1) && (devc->audio_mode & PCM_ENABLE_INPUT)) { - DMAbuf_inputintr(devc->record_dev); - temp = 0; - } - if (temp) //default: - printk(KERN_WARNING "waveartist: Unknown interrupt\n"); - } - if (irqstatus & 0x2) - // We do not use SB mode natively... - printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); - spin_unlock(&waveartist_lock); - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------------------- - * Mixer stuff - */ -struct mix_ent { - unsigned char reg_l; - unsigned char reg_r; - unsigned char shift; - unsigned char max; -}; - -static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = { - { 2, 6, 1, 7 }, /* SOUND_MIXER_VOLUME */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_BASS */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_TREBLE */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_SYNTH */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_PCM */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_SPEAKER */ - { 0, 4, 6, 31 }, /* SOUND_MIXER_LINE */ - { 2, 6, 4, 3 }, /* SOUND_MIXER_MIC */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_CD */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_IMIX */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_ALTPCM */ -#if 0 - { 3, 7, 0, 10 }, /* SOUND_MIXER_RECLEV */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_IGAIN */ -#else - { 0, 0, 0, 0 }, /* SOUND_MIXER_RECLEV */ - { 3, 7, 0, 7 }, /* SOUND_MIXER_IGAIN */ -#endif - { 0, 0, 0, 0 }, /* SOUND_MIXER_OGAIN */ - { 0, 4, 1, 31 }, /* SOUND_MIXER_LINE1 */ - { 1, 5, 6, 31 }, /* SOUND_MIXER_LINE2 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_LINE3 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL1 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL2 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL3 */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEIN */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEOUT */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_VIDEO */ - { 0, 0, 0, 0 }, /* SOUND_MIXER_RADIO */ - { 0, 0, 0, 0 } /* SOUND_MIXER_MONITOR */ -}; - -static void -waveartist_mixer_update(struct wavnc_info *devc, int whichDev) -{ - unsigned int lev_left, lev_right; - - lev_left = devc->levels[whichDev] & 0xff; - lev_right = devc->levels[whichDev] >> 8; - - if (lev_left > 100) - lev_left = 100; - if (lev_right > 100) - lev_right = 100; - -#define SCALE(lev,max) ((lev) * (max) / 100) - - if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT) - whichDev = SOUND_MIXER_VOLUME; - - if (mix_devs[whichDev].reg_l || mix_devs[whichDev].reg_r) { - const struct mix_ent *mix = mix_devs + whichDev; - unsigned int mask, left, right; - - mask = mix->max << mix->shift; - lev_left = SCALE(lev_left, mix->max) << mix->shift; - lev_right = SCALE(lev_right, mix->max) << mix->shift; - - /* read left setting */ - left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | - mix->reg_l << 8); - - /* read right setting */ - right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | - mix->reg_r << 8); - - left = (left & ~mask) | (lev_left & mask); - right = (right & ~mask) | (lev_right & mask); - - /* write left,right back */ - waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); - } else { - switch(whichDev) { - case SOUND_MIXER_PCM: - waveartist_cmd3(devc, WACMD_SET_LEVEL, - SCALE(lev_left, 32767), - SCALE(lev_right, 32767)); - break; - - case SOUND_MIXER_SYNTH: - waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL, - SCALE(lev_left, 32767), - SCALE(lev_right, 32767)); - break; - } - } -} - -/* - * Set the ADC MUX to the specified values. We do NOT do any - * checking of the values passed, since we assume that the - * relevant *_select_input function has done that for us. - */ -static void -waveartist_set_adc_mux(struct wavnc_info *devc, char left_dev, - char right_dev) -{ - unsigned int reg_08, reg_09; - - reg_08 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0800); - reg_09 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0900); - - reg_08 = (reg_08 & ~0x3f) | right_dev << 3 | left_dev; - - waveartist_cmd3(devc, WACMD_SET_MIXER, reg_08, reg_09); -} - -/* - * Decode a recording mask into a mixer selection as follows: - * - * OSS Source WA Source Actual source - * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) - * SOUND_MASK_LINE Line Line in - * SOUND_MASK_LINE1 Aux 1 Aux 1 in - * SOUND_MASK_LINE2 Aux 2 Aux 2 in - * SOUND_MASK_MIC Mic Microphone - */ -static unsigned int -waveartist_select_input(struct wavnc_info *devc, unsigned int recmask, - unsigned char *dev_l, unsigned char *dev_r) -{ - unsigned int recdev = ADC_MUX_NONE; - - if (recmask & SOUND_MASK_IMIX) { - recmask = SOUND_MASK_IMIX; - recdev = ADC_MUX_MIXER; - } else if (recmask & SOUND_MASK_LINE2) { - recmask = SOUND_MASK_LINE2; - recdev = ADC_MUX_AUX2; - } else if (recmask & SOUND_MASK_LINE1) { - recmask = SOUND_MASK_LINE1; - recdev = ADC_MUX_AUX1; - } else if (recmask & SOUND_MASK_LINE) { - recmask = SOUND_MASK_LINE; - recdev = ADC_MUX_LINE; - } else if (recmask & SOUND_MASK_MIC) { - recmask = SOUND_MASK_MIC; - recdev = ADC_MUX_MIC; - } - - *dev_l = *dev_r = recdev; - - return recmask; -} - -static int -waveartist_decode_mixer(struct 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(struct 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 void -waveartist_set_recmask(struct 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 int -waveartist_set_mixer(struct 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 int -waveartist_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) -{ - struct wavnc_info *devc = (struct 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 __user *)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 __user *)arg) ? -EFAULT : 0; - } - - return ret; -} - -static struct mixer_operations waveartist_mixer_operations = -{ - .owner = THIS_MODULE, - .id = "WaveArtist", - .name = "WaveArtist", - .ioctl = waveartist_mixer_ioctl -}; - -static void -waveartist_mixer_reset(struct 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(struct wavnc_info *devc) -{ - struct 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 = kzalloc(sizeof(struct wavnc_port_info), GFP_KERNEL); - if (portc == NULL) - goto nomem; - - 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) -{ - struct 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 (!request_region(hw_config->io_base, 15, hw_config->name)) { - printk(KERN_WARNING "WaveArtist: I/O port conflict\n"); - return 0; - } - - if (hw_config->irq > 15 || hw_config->irq < 0) { - release_region(hw_config->io_base, 15); - printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n", - hw_config->irq); - return 0; - } - - if (hw_config->dma != 3) { - release_region(hw_config->io_base, 15); - 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 __init -attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix) -{ - struct 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; - - 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()) { - setup_timer(&vnc_timer, vnc_slider_tick, - nr_waveartist_devs); - mod_timer(&vnc_timer, jiffies); - - vnc_configure_mixer(devc, 0); - - devc->no_autoselect = 1; - } -#endif - nr_waveartist_devs += 1; - } -} - -static void __exit unload_waveartist(struct address_info *hw) -{ - struct 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 0x80 - -static inline void -vnc_mute_spkr(struct wavnc_info *devc) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&nw_gpio_lock, flags); - nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE); - raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); -} - -static void -vnc_mute_lout(struct 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 int -vnc_volume_slider(struct wavnc_info *devc) -{ - static signed int old_slider_volume; - unsigned long flags; - signed int volume = 255; - - *CSR_TIMER1_LOAD = 0x00ffffff; - - spin_lock_irqsave(&waveartist_lock, flags); - - outb(0xFF, 0x201); - *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; - - while (volume && (inb(0x201) & 0x01)) - volume--; - - *CSR_TIMER1_CNTL = 0; - - spin_unlock_irqrestore(&waveartist_lock,flags); - - volume = 0x00ffffff - *CSR_TIMER1_VALUE; - - -#ifndef REVERSE - volume = 150 - (volume >> 5); -#else - volume = (volume >> 6) - 25; -#endif - - if (volume < 0) - volume = 0; - - if (volume > 100) - volume = 100; - - /* - * slider quite often reads +-8, so debounce this random noise - */ - if (abs(volume - old_slider_volume) > 7) { - old_slider_volume = volume; - - if (debug_flg & DEBUG_MIXER) - printk(KERN_DEBUG "Slider volume: %d.\n", volume); - } - - return old_slider_volume; -} - -/* - * Decode a recording mask into a mixer selection on the NetWinder - * as follows: - * - * OSS Source WA Source Actual source - * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) - * SOUND_MASK_LINE Line Line in - * SOUND_MASK_LINE1 Left Mic Handset - * SOUND_MASK_PHONEIN Left Aux Telephone microphone - * SOUND_MASK_MIC Right Mic Builtin microphone - */ -static unsigned int -netwinder_select_input(struct wavnc_info *devc, unsigned int recmask, - unsigned char *dev_l, unsigned char *dev_r) -{ - unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE; - - if (recmask & SOUND_MASK_IMIX) { - recmask = SOUND_MASK_IMIX; - recdev_l = ADC_MUX_MIXER; - recdev_r = ADC_MUX_MIXER; - } else if (recmask & SOUND_MASK_LINE) { - recmask = SOUND_MASK_LINE; - recdev_l = ADC_MUX_LINE; - recdev_r = ADC_MUX_LINE; - } else if (recmask & SOUND_MASK_LINE1) { - recmask = SOUND_MASK_LINE1; - waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ - recdev_l = ADC_MUX_MIC; - recdev_r = ADC_MUX_NONE; - } else if (recmask & SOUND_MASK_PHONEIN) { - recmask = SOUND_MASK_PHONEIN; - waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ - recdev_l = ADC_MUX_AUX1; - recdev_r = ADC_MUX_NONE; - } else if (recmask & SOUND_MASK_MIC) { - recmask = SOUND_MASK_MIC; - waveartist_cmd1(devc, WACMD_SET_MONO | 0x100); /* right */ - recdev_l = ADC_MUX_NONE; - recdev_r = ADC_MUX_MIC; - } - - *dev_l = recdev_l; - *dev_r = recdev_r; - - return recmask; -} - -static int -netwinder_decode_mixer(struct 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_IGAIN: - devc->levels[dev] = lev_l | lev_r << 8; - break; - - case SOUND_MIXER_MIC: /* right mic only */ - devc->levels[SOUND_MIXER_MIC] &= 0xff; - devc->levels[SOUND_MIXER_MIC] |= lev_l << 8; - break; - - case SOUND_MIXER_LINE1: /* left mic only */ - devc->levels[SOUND_MIXER_MIC] &= 0xff00; - devc->levels[SOUND_MIXER_MIC] |= lev_l; - dev = SOUND_MIXER_MIC; - break; - - case SOUND_MIXER_PHONEIN: /* left aux only */ - devc->levels[SOUND_MIXER_LINE1] = lev_l; - dev = SOUND_MIXER_LINE1; - break; - - case SOUND_MIXER_IMIX: - case SOUND_MIXER_PHONEOUT: - break; - - default: - dev = -EINVAL; - break; - } - return dev; -} - -static int netwinder_get_mixer(struct wavnc_info *devc, int dev) -{ - int levels; - - switch (dev) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_SYNTH: - case SOUND_MIXER_PCM: - case SOUND_MIXER_LINE: - case SOUND_MIXER_IGAIN: - levels = devc->levels[dev]; - break; - - case SOUND_MIXER_MIC: /* builtin mic: right mic only */ - levels = devc->levels[SOUND_MIXER_MIC] >> 8; - levels |= levels << 8; - break; - - case SOUND_MIXER_LINE1: /* handset mic: left mic only */ - levels = devc->levels[SOUND_MIXER_MIC] & 0xff; - levels |= levels << 8; - break; - - case SOUND_MIXER_PHONEIN: /* phone mic: left aux1 only */ - levels = devc->levels[SOUND_MIXER_LINE1] & 0xff; - levels |= levels << 8; - break; - - default: - levels = 0; - } - - return levels; -} - -/* - * Waveartist specific mixer information. - */ -static const struct waveartist_mixer_info netwinder_mixer = { - .supported_devs = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | - SOUND_MASK_PCM | SOUND_MASK_SPEAKER | - SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_IMIX | SOUND_MASK_LINE1 | - SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT| - SOUND_MASK_IGAIN, - - .recording_devs = SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_IMIX | SOUND_MASK_LINE1 | - SOUND_MASK_PHONEIN, - - .stereo_devs = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | - SOUND_MASK_PCM | SOUND_MASK_LINE | - SOUND_MASK_IMIX | SOUND_MASK_IGAIN, - - .select_input = netwinder_select_input, - .decode_mixer = netwinder_decode_mixer, - .get_mixer = netwinder_get_mixer, -}; - -static void -vnc_configure_mixer(struct wavnc_info *devc, unsigned int recmask) -{ - if (!devc->no_autoselect) { - if (devc->handset_detect) { - recmask = SOUND_MASK_LINE1; - devc->spkr_mute_state = devc->line_mute_state = 1; - } else if (devc->telephone_detect) { - recmask = SOUND_MASK_PHONEIN; - devc->spkr_mute_state = devc->line_mute_state = 1; - } else { - /* unless someone has asked for LINE-IN, - * we default to MIC - */ - if ((devc->recmask & SOUND_MASK_LINE) == 0) - devc->recmask = SOUND_MASK_MIC; - devc->spkr_mute_state = devc->line_mute_state = 0; - } - vnc_mute_spkr(devc); - vnc_mute_lout(devc); - - if (recmask != devc->recmask) - waveartist_set_recmask(devc, recmask); - } -} - -static int -vnc_slider(struct wavnc_info *devc) -{ - signed int slider_volume; - unsigned int temp, old_hs, old_td; - - /* - * read the "buttons" state. - * Bit 4 = 0 means handset present - * Bit 5 = 1 means phone offhook - */ - temp = inb(0x201); - - old_hs = devc->handset_detect; - old_td = devc->telephone_detect; - - devc->handset_detect = !(temp & 0x10); - devc->telephone_detect = !!(temp & 0x20); - - if (!devc->no_autoselect && - (old_hs != devc->handset_detect || - old_td != devc->telephone_detect)) - vnc_configure_mixer(devc, devc->recmask); - - slider_volume = vnc_volume_slider(devc); - - /* - * If we're using software controlled volume, and - * the slider moves by more than 20%, then we - * switch back to slider controlled volume. - */ - if (abs(devc->slider_vol - slider_volume) > 20) - devc->use_slider = 1; - - /* - * use only left channel - */ - temp = levels[SOUND_MIXER_VOLUME] & 0xFF; - - if (slider_volume != temp && devc->use_slider) { - devc->slider_vol = slider_volume; - - waveartist_set_mixer(devc, SOUND_MIXER_VOLUME, - slider_volume | slider_volume << 8); - - return 1; - } - - return 0; -} - -static void -vnc_slider_tick(unsigned long data) -{ - int next_timeout; - - if (vnc_slider(adev_info + data)) - next_timeout = 5; // mixer reported change - else - next_timeout = VNC_TIMER_PERIOD; - - mod_timer(&vnc_timer, jiffies + next_timeout); -} - -static int -vnc_private_ioctl(int dev, unsigned int cmd, int __user * arg) -{ - struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; - int val; - - switch (cmd) { - case SOUND_MIXER_PRIVATE1: - { - u_int prev_spkr_mute, prev_line_mute, prev_auto_state; - int val; - - if (get_user(val, arg)) - return -EFAULT; - - /* check if parameter is logical */ - if (val & ~(VNC_MUTE_INTERNAL_SPKR | - VNC_MUTE_LINE_OUT | - VNC_DISABLE_AUTOSWITCH)) - return -EINVAL; - - prev_auto_state = devc->no_autoselect; - prev_spkr_mute = devc->spkr_mute_state; - prev_line_mute = devc->line_mute_state; - - devc->no_autoselect = (val & VNC_DISABLE_AUTOSWITCH) ? 1 : 0; - devc->spkr_mute_state = (val & VNC_MUTE_INTERNAL_SPKR) ? 1 : 0; - devc->line_mute_state = (val & VNC_MUTE_LINE_OUT) ? 1 : 0; - - if (prev_spkr_mute != devc->spkr_mute_state) - vnc_mute_spkr(devc); - - if (prev_line_mute != devc->line_mute_state) - vnc_mute_lout(devc); - - if (prev_auto_state != devc->no_autoselect) - vnc_configure_mixer(devc, devc->recmask); - - return 0; - } - - case SOUND_MIXER_PRIVATE2: - if (get_user(val, arg)) - return -EFAULT; - - switch (val) { -#define VNC_SOUND_PAUSE 0x53 //to pause the DSP -#define VNC_SOUND_RESUME 0x57 //to unpause the DSP - case VNC_SOUND_PAUSE: - waveartist_cmd1(devc, 0x16); - break; - - case VNC_SOUND_RESUME: - waveartist_cmd1(devc, 0x18); - break; - - default: - return -EINVAL; - } - return 0; - - /* private ioctl to allow bulk access to waveartist */ - case SOUND_MIXER_PRIVATE3: - { - unsigned long flags; - int mixer_reg[15], i, val; - - if (get_user(val, arg)) - return -EFAULT; - if (copy_from_user(mixer_reg, (void *)val, sizeof(mixer_reg))) - return -EFAULT; - - switch (mixer_reg[14]) { - case MIXER_PRIVATE3_RESET: - waveartist_mixer_reset(devc); - break; - - case MIXER_PRIVATE3_WRITE: - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[0], mixer_reg[4]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[1], mixer_reg[5]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[2], mixer_reg[6]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[3], mixer_reg[7]); - waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[8], mixer_reg[9]); - - waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[10], mixer_reg[11]); - waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[12], mixer_reg[13]); - break; - - case MIXER_PRIVATE3_READ: - spin_lock_irqsave(&waveartist_lock, flags); - - for (i = 0x30; i < 14 << 8; i += 1 << 8) - waveartist_cmd(devc, 1, &i, 1, mixer_reg + (i >> 8)); - - spin_unlock_irqrestore(&waveartist_lock, flags); - - if (copy_to_user((void *)val, mixer_reg, sizeof(mixer_reg))) - return -EFAULT; - break; - - default: - return -EINVAL; - } - return 0; - } - - /* read back the state from PRIVATE1 */ - case SOUND_MIXER_PRIVATE4: - val = (devc->spkr_mute_state ? VNC_MUTE_INTERNAL_SPKR : 0) | - (devc->line_mute_state ? VNC_MUTE_LINE_OUT : 0) | - (devc->handset_detect ? VNC_HANDSET_DETECT : 0) | - (devc->telephone_detect ? VNC_PHONE_DETECT : 0) | - (devc->no_autoselect ? VNC_DISABLE_AUTOSWITCH : 0); - - return put_user(val, arg) ? -EFAULT : 0; - } - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - /* - * special case for master volume: if we - * received this call - switch from hw - * volume control to a software volume - * control, till the hw volume is modified - * to signal that user wants to be back in - * hardware... - */ - if ((cmd & 0xff) == SOUND_MIXER_VOLUME) - devc->use_slider = 0; - - /* speaker output */ - if ((cmd & 0xff) == SOUND_MIXER_SPEAKER) { - unsigned int val, l, r; - - if (get_user(val, arg)) - return -EFAULT; - - l = val & 0x7f; - r = (val & 0x7f00) >> 8; - val = (l + r) / 2; - devc->levels[SOUND_MIXER_SPEAKER] = val | (val << 8); - devc->spkr_mute_state = (val <= 50); - vnc_mute_spkr(devc); - return 0; - } - } - - return -ENOIOCTLCMD; -} - -#endif - -static struct address_info cfg; - -static int attached; - -static int __initdata io = 0; -static int __initdata irq = 0; -static int __initdata dma = 0; -static int __initdata dma2 = 0; - - -static int __init init_waveartist(void) -{ - const struct waveartist_mixer_info *mix; - - if (!io && machine_is_netwinder()) { - /* - * The NetWinder WaveArtist is at a fixed address. - * If the user does not supply an address, use the - * well-known parameters. - */ - io = 0x250; - irq = 12; - dma = 3; - dma2 = 7; - } - - mix = &waveartist_mixer; -#ifdef CONFIG_ARCH_NETWINDER - if (machine_is_netwinder()) - mix = &netwinder_mixer; -#endif - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - if (!probe_waveartist(&cfg)) - return -ENODEV; - - attach_waveartist(&cfg, mix); - attached = 1; - - return 0; -} - -static void __exit cleanup_waveartist(void) -{ - if (attached) - unload_waveartist(&cfg); -} - -module_init(init_waveartist); -module_exit(cleanup_waveartist); - -#ifndef MODULE -static int __init setup_waveartist(char *str) -{ - /* io, irq, dma, dma2 */ - int ints[5]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - - return 1; -} -__setup("waveartist=", setup_waveartist); -#endif - -MODULE_DESCRIPTION("Rockwell WaveArtist RWA-010 sound driver"); -module_param_hw(io, int, ioport, 0); /* IO base */ -module_param_hw(irq, int, irq, 0); /* IRQ */ -module_param_hw(dma, int, dma, 0); /* DMA */ -module_param_hw(dma2, int, dma, 0); /* DMA2 */ -MODULE_LICENSE("GPL"); diff --git a/sound/oss/waveartist.h b/sound/oss/waveartist.h deleted file mode 100644 index f18d74b26483..000000000000 --- a/sound/oss/waveartist.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * linux/sound/oss/waveartist.h - * - * def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder - */ - -//registers -#define CMDR 0 -#define DATR 2 -#define CTLR 4 -#define STATR 5 -#define IRQSTAT 12 - -//bit defs -//reg STATR -#define CMD_WE 0x80 -#define CMD_RF 0x40 -#define DAT_WE 0x20 -#define DAT_RF 0x10 - -#define IRQ_REQ 0x08 -#define DMA1 0x04 -#define DMA0 0x02 - -//bit defs -//reg CTLR -#define CMD_WEIE 0x80 -#define CMD_RFIE 0x40 -#define DAT_WEIE 0x20 -#define DAT_RFIE 0x10 - -#define RESET 0x08 -#define DMA1_IE 0x04 -#define DMA0_IE 0x02 -#define IRQ_ACK 0x01 - -//commands - -#define WACMD_SYSTEMID 0x00 -#define WACMD_GETREV 0x00 -#define WACMD_INPUTFORMAT 0x10 //0-8S, 1-16S, 2-8U -#define WACMD_INPUTCHANNELS 0x11 //1-Mono, 2-Stereo -#define WACMD_INPUTSPEED 0x12 //sampling rate -#define WACMD_INPUTDMA 0x13 //0-8bit, 1-16bit, 2-PIO -#define WACMD_INPUTSIZE 0x14 //samples to interrupt -#define WACMD_INPUTSTART 0x15 //start ADC -#define WACMD_INPUTPAUSE 0x16 //pause ADC -#define WACMD_INPUTSTOP 0x17 //stop ADC -#define WACMD_INPUTRESUME 0x18 //resume ADC -#define WACMD_INPUTPIO 0x19 //PIO ADC - -#define WACMD_OUTPUTFORMAT 0x20 //0-8S, 1-16S, 2-8U -#define WACMD_OUTPUTCHANNELS 0x21 //1-Mono, 2-Stereo -#define WACMD_OUTPUTSPEED 0x22 //sampling rate -#define WACMD_OUTPUTDMA 0x23 //0-8bit, 1-16bit, 2-PIO -#define WACMD_OUTPUTSIZE 0x24 //samples to interrupt -#define WACMD_OUTPUTSTART 0x25 //start ADC -#define WACMD_OUTPUTPAUSE 0x26 //pause ADC -#define WACMD_OUTPUTSTOP 0x27 //stop ADC -#define WACMD_OUTPUTRESUME 0x28 //resume ADC -#define WACMD_OUTPUTPIO 0x29 //PIO ADC - -#define WACMD_GET_LEVEL 0x30 -#define WACMD_SET_LEVEL 0x31 -#define WACMD_SET_MIXER 0x32 -#define WACMD_RST_MIXER 0x33 -#define WACMD_SET_MONO 0x34 - -/* - * Definitions for left/right recording input mux - */ -#define ADC_MUX_NONE 0 -#define ADC_MUX_MIXER 1 -#define ADC_MUX_LINE 2 -#define ADC_MUX_AUX2 3 -#define ADC_MUX_AUX1 4 -#define ADC_MUX_MIC 5 - -/* - * Definitions for mixer gain settings - */ -#define MIX_GAIN_LINE 0 /* line in */ -#define MIX_GAIN_AUX1 1 /* aux1 */ -#define MIX_GAIN_AUX2 2 /* aux2 */ -#define MIX_GAIN_XMIC 3 /* crossover mic */ -#define MIX_GAIN_MIC 4 /* normal mic */ -#define MIX_GAIN_PREMIC 5 /* preamp mic */ -#define MIX_GAIN_OUT 6 /* output */ -#define MIX_GAIN_MONO 7 /* mono in */ - -int wa_sendcmd(unsigned int cmd); -int wa_writecmd(unsigned int cmd, unsigned int arg); diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 70d023a85bf5..720361455c60 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -573,10 +573,8 @@ static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream) static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream) { - struct snd_card_asihpi_pcm *dpcm; struct snd_card_asihpi *card; - dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data; card = snd_pcm_substream_chip(substream); hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, @@ -749,9 +747,9 @@ static inline unsigned int modulo_min(unsigned int a, unsigned int b, /** Timer function, equivalent to interrupt service routine for cards */ -static void snd_card_asihpi_timer_function(unsigned long data) +static void snd_card_asihpi_timer_function(struct timer_list *t) { - struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data; + struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer); struct snd_pcm_substream *substream = dpcm->substream; struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime; @@ -863,7 +861,6 @@ static void snd_card_asihpi_timer_function(unsigned long data) snd_pcm_group_for_each_entry(s, substream) { struct snd_card_asihpi_pcm *ds = s->runtime->private_data; - runtime = s->runtime; /* don't link Cap and Play */ if (substream->stream != s->stream) @@ -948,7 +945,7 @@ static void snd_card_asihpi_int_task(unsigned long data) asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; if (asihpi->llmode_streampriv) snd_card_asihpi_timer_function( - (unsigned long)asihpi->llmode_streampriv); + &asihpi->llmode_streampriv->timer); } static void snd_card_asihpi_isr(struct hpi_adapter *a) @@ -1059,8 +1056,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) If internal and other stream playing, can't switch */ - setup_timer(&dpcm->timer, snd_card_asihpi_timer_function, - (unsigned long) dpcm); + timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0); dpcm->substream = substream; runtime->private_data = dpcm; runtime->private_free = snd_card_asihpi_runtime_free; @@ -1240,8 +1236,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) if (err) return -EIO; - setup_timer(&dpcm->timer, snd_card_asihpi_timer_function, - (unsigned long) dpcm); + timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0); dpcm->substream = substream; runtime->private_data = dpcm; runtime->private_free = snd_card_asihpi_runtime_free; diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index c308a4f70550..4083c8b01619 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2628,7 +2628,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) else edi = 0x1ffff; } else { - i = edi = 0x800; + edi = 0x800; } /* this_04 and this_08 are the CASp4Src's (samplerate converters) */ vortex_src_setupchannel(vortex, this_04, edi, 0, 1, diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 8f945341720b..08e874e9a7f6 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -63,9 +63,9 @@ struct ct_timer { * system-timer-based updates */ -static void ct_systimer_callback(unsigned long data) +static void ct_systimer_callback(struct timer_list *t) { - struct ct_timer_instance *ti = (struct ct_timer_instance *)data; + struct ct_timer_instance *ti = from_timer(ti, t, timer); struct snd_pcm_substream *substream = ti->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct ct_atc_pcm *apcm = ti->apcm; @@ -93,8 +93,7 @@ static void ct_systimer_callback(unsigned long data) static void ct_systimer_init(struct ct_timer_instance *ti) { - setup_timer(&ti->timer, ct_systimer_callback, - (unsigned long)ti); + timer_setup(&ti->timer, ct_systimer_callback, 0); } static void ct_systimer_start(struct ct_timer_instance *ti) diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 8c685ddb1a41..6045a115cffe 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -199,9 +199,9 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream) -static void snd_echo_midi_output_write(unsigned long data) +static void snd_echo_midi_output_write(struct timer_list *t) { - struct echoaudio *chip = (struct echoaudio *)data; + struct echoaudio *chip = from_timer(chip, t, timer); unsigned long flags; int bytes, sent, time; unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1]; @@ -257,8 +257,8 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream spin_lock_irq(&chip->lock); if (up) { if (!chip->tinuse) { - setup_timer(&chip->timer, snd_echo_midi_output_write, - (unsigned long)chip); + timer_setup(&chip->timer, snd_echo_midi_output_write, + 0); chip->tinuse = 1; } } else { @@ -273,7 +273,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream spin_unlock_irq(&chip->lock); if (up && !chip->midi_full) - snd_echo_midi_output_write((unsigned long)chip); + snd_echo_midi_output_write(&chip->timer); } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index cf05229b569b..bde0d1954f56 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -280,7 +280,6 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; unsigned int val, tmp, n; val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); - tmp = (val >> 16) & 0x8; for (n = 0; n < 4; n++) { tmp = val >> (16 + (n*4)); if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index d4cd6451fdca..39f79a6b5283 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -732,7 +732,7 @@ static void snd_es1371_codec_wait(struct snd_ac97 *ac97) static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) { - unsigned int n, truncm, freq, result; + unsigned int n, truncm, freq; mutex_lock(&ensoniq->src_mutex); n = rate / 3000; @@ -740,7 +740,6 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) n--; truncm = (21 * n - 1) | 1; freq = ((48000UL << 15) / rate) * n; - result = (48000UL << 15) / (freq / n); if (rate >= 24000) { if (truncm > 239) truncm = 239; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a0989d231fd0..e018ecbf78a8 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -977,7 +977,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) hda_nid_t fg; int err; - err = snd_hdac_refresh_widget_sysfs(&codec->core); + err = snd_hdac_refresh_widgets(&codec->core, true); if (err < 0) return err; @@ -1823,7 +1823,9 @@ struct slave_init_arg { }; /* initialize the slave volume with 0dB via snd_ctl_apply_vmaster_slaves() */ -static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg) +static int init_slave_0dB(struct snd_kcontrol *slave, + struct snd_kcontrol *kctl, + void *_arg) { struct slave_init_arg *arg = _arg; int _tlv[4]; @@ -1860,7 +1862,7 @@ static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg) arg->step = step; val = -tlv[2] / step; if (val > 0) { - put_kctl_with_value(kctl, val); + put_kctl_with_value(slave, val); return val; } @@ -1868,7 +1870,9 @@ static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg) } /* unmute the slave via snd_ctl_apply_vmaster_slaves() */ -static int init_slave_unmute(struct snd_kcontrol *slave, void *_arg) +static int init_slave_unmute(struct snd_kcontrol *slave, + struct snd_kcontrol *kctl, + void *_arg) { return put_kctl_with_value(slave, 1); } diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 28e265a88383..5cc65093d941 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -795,6 +795,8 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, hda_nid_t nid = path->path[i]; nums = snd_hda_get_conn_list(codec, nid, &conn); + if (nums < 0) + return; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_PIN || (type == AC_WID_AUD_IN && codec->single_adc_amp)) { diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f958d8d54d15..c71dcacea807 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2463,6 +2463,9 @@ static const struct pci_device_id azx_ids[] = { /* AMD Hudson */ { PCI_DEVICE(0x1022, 0x780d), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, + /* AMD Raven */ + { PCI_DEVICE(0x1022, 0x15e3), + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* ATI HDMI */ { PCI_DEVICE(0x1002, 0x0002), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 3e73d5c6ccfc..768ea8651993 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -27,6 +27,7 @@ #include <linux/mutex.h> #include <linux/module.h> #include <linux/firmware.h> +#include <linux/kernel.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -3605,8 +3606,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - unsigned int items = sizeof(ca0132_voicefx_presets) - / sizeof(struct ct_voicefx_preset); + unsigned int items = ARRAY_SIZE(ca0132_voicefx_presets); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -3635,10 +3635,8 @@ static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol, struct ca0132_spec *spec = codec->spec; int i, err = 0; int sel = ucontrol->value.enumerated.item[0]; - unsigned int items = sizeof(ca0132_voicefx_presets) - / sizeof(struct ct_voicefx_preset); - if (sel >= items) + if (sel >= ARRAY_SIZE(ca0132_voicefx_presets)) return 0; codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n", diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 546d515f3c1f..921a10eff43a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -341,6 +341,9 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0299: alc_update_coef_idx(codec, 0x10, 1<<9, 0); break; + case 0x10ec0275: + alc_update_coef_idx(codec, 0xe, 0, 1<<0); + break; case 0x10ec0293: alc_update_coef_idx(codec, 0xa, 1<<13, 0); break; @@ -1803,6 +1806,7 @@ enum { ALC887_FIXUP_ASUS_BASS, ALC887_FIXUP_BASS_CHMAP, ALC1220_FIXUP_GB_DUAL_CODECS, + ALC1220_FIXUP_CLEVO_P950, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -2020,6 +2024,23 @@ static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec, } } +static void alc1220_fixup_clevo_p950(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + hda_nid_t conn1[1] = { 0x0c }; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + alc_update_coef_idx(codec, 0x7, 0, 0x3c3); + /* We therefore want to make sure 0x14 (front headphone) and + * 0x1b (speakers) use the stereo DAC 0x02 + */ + snd_hda_override_conn_list(codec, 0x14, 1, conn1); + snd_hda_override_conn_list(codec, 0x1b, 1, conn1); +} + static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { .type = HDA_FIXUP_PINS, @@ -2260,6 +2281,10 @@ static const struct hda_fixup alc882_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc1220_fixup_gb_dual_codecs, }, + [ALC1220_FIXUP_CLEVO_P950] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc1220_fixup_clevo_p950, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2333,6 +2358,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), + SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530), @@ -6366,6 +6392,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {.id = ALC292_FIXUP_TPT460, .name = "tpt460"}, {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, + {.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"}, {} }; #define ALC225_STANDARD_PINS \ @@ -6428,6 +6455,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { ALC225_STANDARD_PINS, {0x12, 0xb7a60130}, {0x1b, 0x90170110}), + SND_HDA_PIN_QUIRK(0x10ec0233, 0x8086, "Intel NUC Skull Canyon", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x1b, 0x01111010}, + {0x1e, 0x01451130}, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60140}, {0x14, 0x90170110}, @@ -6544,6 +6575,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x14, 0x90170110}, {0x1b, 0x90a70130}, {0x21, 0x03211020}), + SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0xb7a60130}, + {0x13, 0xb8a61140}, + {0x16, 0x90170110}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, {0x12, 0x90a60130}, {0x14, 0x90170110}, @@ -6858,7 +6894,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0703: spec->codec_variant = ALC269_TYPE_ALC700; spec->gen.mixer_nid = 0; /* ALC700 does not have any loopback mixer path */ - alc_update_coef_idx(codec, 0x4a, 0, 1 << 15); /* Combo jack auto trigger control */ + alc_update_coef_idx(codec, 0x4a, 1 << 15, 0); /* Combo jack auto trigger control */ break; } diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 0e66afa403a3..f1fe497c2f9d 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2285,7 +2285,7 @@ static unsigned char snd_ice1712_read_i2c(struct snd_ice1712 *ice, static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice, const char *modelname) { - int dev = 0xa0; /* EEPROM device address */ + int dev = ICE_I2C_EEPROM_ADDR; /* I2C EEPROM device address */ unsigned int i, size; struct snd_ice1712_card_info * const *tbl, *c; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 5cfba09c9761..8ae8742662a5 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -218,8 +218,9 @@ /* - * + * I2C EEPROM Address */ +#define ICE_I2C_EEPROM_ADDR 0xA0 struct snd_ice1712; diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 04cd71c74e5c..c7b007164c99 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -599,9 +599,9 @@ static void snd_korg1212_SendStopAndWait(struct snd_korg1212 *korg1212) } /* timer callback for checking the ack of stop request */ -static void snd_korg1212_timer_func(unsigned long data) +static void snd_korg1212_timer_func(struct timer_list *t) { - struct snd_korg1212 *korg1212 = (struct snd_korg1212 *) data; + struct snd_korg1212 *korg1212 = from_timer(korg1212, t, timer); unsigned long flags; spin_lock_irqsave(&korg1212->lock, flags); @@ -2189,8 +2189,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, init_waitqueue_head(&korg1212->wait); spin_lock_init(&korg1212->lock); mutex_init(&korg1212->open_mutex); - setup_timer(&korg1212->timer, snd_korg1212_timer_func, - (unsigned long)korg1212); + timer_setup(&korg1212->timer, snd_korg1212_timer_func, 0); korg1212->irq = -1; korg1212->clkSource = K1212_CLKIDX_Local; diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h index 7a1e8f9c48e7..24d97721c247 100644 --- a/sound/pci/oxygen/xonar_dg.h +++ b/sound/pci/oxygen/xonar_dg.h @@ -52,6 +52,6 @@ void dg_suspend(struct oxygen *chip); void dg_resume(struct oxygen *chip); void dg_cleanup(struct oxygen *chip); -extern struct oxygen_model model_xonar_dg; +extern const struct oxygen_model model_xonar_dg; #endif diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c index b885dac28a09..d22fbe8aebd0 100644 --- a/sound/pci/oxygen/xonar_dg_mixer.c +++ b/sound/pci/oxygen/xonar_dg_mixer.c @@ -449,7 +449,7 @@ static int dg_mixer_init(struct oxygen *chip) return 0; } -struct oxygen_model model_xonar_dg = { +const struct oxygen_model model_xonar_dg = { .longname = "C-Media Oxygen HD Audio", .chip = "CMI8786", .init = dg_init, diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 9f0f73875f01..1bff4b1b39cd 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1410,9 +1410,9 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore (&hdsp->lock, flags); } -static void snd_hdsp_midi_output_timer(unsigned long data) +static void snd_hdsp_midi_output_timer(struct timer_list *t) { - struct hdsp_midi *hmidi = (struct hdsp_midi *) data; + struct hdsp_midi *hmidi = from_timer(hmidi, t, timer); unsigned long flags; snd_hdsp_midi_output_write(hmidi); @@ -1439,8 +1439,8 @@ static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { - setup_timer(&hmidi->timer, snd_hdsp_midi_output_timer, - (unsigned long) hmidi); + timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer, + 0); mod_timer(&hmidi->timer, 1 + jiffies); hmidi->istimer++; } diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index f20d42714e4d..4c59983158e0 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1946,9 +1946,9 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) spin_unlock_irqrestore (&hdspm->lock, flags); } -static void snd_hdspm_midi_output_timer(unsigned long data) +static void snd_hdspm_midi_output_timer(struct timer_list *t) { - struct hdspm_midi *hmidi = (struct hdspm_midi *) data; + struct hdspm_midi *hmidi = from_timer(hmidi, t, timer); unsigned long flags; snd_hdspm_midi_output_write(hmidi); @@ -1976,8 +1976,8 @@ snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { - setup_timer(&hmidi->timer, snd_hdspm_midi_output_timer, - (unsigned long) hmidi); + timer_setup(&hmidi->timer, + snd_hdspm_midi_output_timer, 0); mod_timer(&hmidi->timer, 1 + jiffies); hmidi->istimer++; } diff --git a/sound/sh/aica.c b/sound/sh/aica.c index fdc680ae8aa0..2b26311405a4 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -299,14 +299,14 @@ static void run_spu_dma(struct work_struct *work) } } -static void aica_period_elapsed(unsigned long timer_var) +static void aica_period_elapsed(struct timer_list *t) { + struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard, + t, timer); + struct snd_pcm_substream *substream = dreamcastcard->timer_substream; /*timer function - so cannot sleep */ int play_period; struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *substream; - struct snd_card_aica *dreamcastcard; - substream = (struct snd_pcm_substream *) timer_var; runtime = substream->runtime; dreamcastcard = substream->pcm->private_data; /* Have we played out an additional period? */ @@ -336,12 +336,12 @@ static void spu_begin_dma(struct snd_pcm_substream *substream) /*get the queue to do the work */ schedule_work(&(dreamcastcard->spu_dma_work)); /* Timer may already be running */ - if (unlikely(dreamcastcard->timer.data)) { + if (unlikely(dreamcastcard->timer_substream)) { mod_timer(&dreamcastcard->timer, jiffies + 4); return; } - setup_timer(&dreamcastcard->timer, aica_period_elapsed, - (unsigned long) substream); + timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0); + dreamcastcard->timer_substream = substream; mod_timer(&dreamcastcard->timer, jiffies + 4); } @@ -379,7 +379,7 @@ static int snd_aicapcm_pcm_close(struct snd_pcm_substream { struct snd_card_aica *dreamcastcard = substream->pcm->private_data; flush_work(&(dreamcastcard->spu_dma_work)); - if (dreamcastcard->timer.data) + if (dreamcastcard->timer_substream) del_timer(&dreamcastcard->timer); kfree(dreamcastcard->channel); spu_disable(); @@ -600,7 +600,7 @@ static int snd_aica_probe(struct platform_device *devptr) { int err; struct snd_card_aica *dreamcastcard; - dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL); + dreamcastcard = kzalloc(sizeof(struct snd_card_aica), GFP_KERNEL); if (unlikely(!dreamcastcard)) return -ENOMEM; err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER, @@ -619,8 +619,6 @@ static int snd_aica_probe(struct platform_device *devptr) err = snd_aicapcmchip(dreamcastcard, 0); if (unlikely(err < 0)) goto freedreamcast; - dreamcastcard->timer.data = 0; - dreamcastcard->channel = NULL; /* Add basic controls */ err = add_aicamixer_controls(dreamcastcard); if (unlikely(err < 0)) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 5f24df4fae8e..f020d2d1eef4 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3346,9 +3346,9 @@ static irqreturn_t rt5645_irq(int irq, void *data) return IRQ_HANDLED; } -static void rt5645_btn_check_callback(unsigned long data) +static void rt5645_btn_check_callback(struct timer_list *t) { - struct rt5645_priv *rt5645 = (struct rt5645_priv *)data; + struct rt5645_priv *rt5645 = from_timer(rt5645, t, btn_check_timer); queue_delayed_work(system_power_efficient_wq, &rt5645->jack_detect_work, msecs_to_jiffies(5)); @@ -3954,8 +3954,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); } - setup_timer(&rt5645->btn_check_timer, - rt5645_btn_check_callback, (unsigned long)rt5645); + timer_setup(&rt5645->btn_check_timer, rt5645_btn_check_callback, 0); INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work); diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 1773ff84ee3b..3b895b4b451c 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -106,10 +106,12 @@ static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = { { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, }, }; +#define to_twl6040(codec) dev_get_drvdata((codec)->dev->parent) + static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg) { struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); u8 value; if (reg >= TWL6040_CACHEREGNUM) @@ -171,7 +173,7 @@ static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec, static int twl6040_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); if (reg >= TWL6040_CACHEREGNUM) return -EIO; @@ -541,7 +543,7 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec) if (snd_soc_dapm_get_pin_status(dapm, "HSOR") || snd_soc_dapm_get_pin_status(dapm, "HSOL")) { - u8 val = snd_soc_read(codec, TWL6040_REG_HSLCTL); + u8 val = twl6040_read(codec, TWL6040_REG_HSLCTL); if (val & TWL6040_HSDACMODE) /* HSDACL in LP mode */ return -8; /* -8dB */ @@ -572,7 +574,7 @@ EXPORT_SYMBOL_GPL(twl6040_get_trim_value); int twl6040_get_hs_step_size(struct snd_soc_codec *codec) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3) /* For ES under ES_1.3 HS step is 2 mV */ @@ -830,7 +832,7 @@ static const struct snd_soc_dapm_route intercon[] = { static int twl6040_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int ret = 0; @@ -922,7 +924,7 @@ static int twl6040_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int ret; @@ -964,7 +966,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id, int mute) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int hslctl, hsrctl, earctl; int hflctl, hfrctl; @@ -1108,7 +1110,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = { static int twl6040_probe(struct snd_soc_codec *codec) { struct twl6040_data *priv; - struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent); struct platform_device *pdev = to_platform_device(codec->dev); int ret = 0; @@ -1119,7 +1120,6 @@ static int twl6040_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, priv); priv->codec = codec; - codec->control_data = twl6040; priv->plug_irq = platform_get_irq(pdev, 0); if (priv->plug_irq < 0) { @@ -1158,8 +1158,6 @@ static int twl6040_remove(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .probe = twl6040_probe, .remove = twl6040_remove, - .read = twl6040_read, - .write = twl6040_write, .set_bias_level = twl6040_set_bias_level, .suspend_bias_off = true, .ignore_pmdown_time = true, diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index bb8be10b8437..7b49d04e3c60 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -34,6 +34,11 @@ config SND_SOC_INTEL_SST_TOPLEVEL depends on X86 || COMPILE_TEST select SND_SOC_INTEL_MACH select SND_SOC_INTEL_COMMON + help + Intel ASoC Audio Drivers. If you have a Intel machine that + has audio controller with a DSP and I2S or DMIC port, then + enable this option by saying Y or M + If unsure select "N". config SND_SOC_INTEL_HASWELL tristate "Intel ASoC SST driver for Haswell/Broadwell" diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 6c49f3d6fd96..d40219678700 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -260,7 +260,7 @@ static bool cx81801_cmd_pending; static bool ams_delta_muted; static DEFINE_SPINLOCK(ams_delta_lock); -static void cx81801_timeout(unsigned long data) +static void cx81801_timeout(struct timer_list *unused) { int muted; @@ -349,7 +349,7 @@ static void cx81801_receive(struct tty_struct *tty, /* First modem response, complete setup procedure */ /* Initialize timer used for config pulse generation */ - setup_timer(&cx81801_timer, cx81801_timeout, 0); + timer_setup(&cx81801_timer, cx81801_timeout, 0); v253_ops.receive_buf(tty, cp, fp, count); diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 8382ffa3bcaf..2472144b329e 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -165,7 +165,7 @@ static bool xtfpga_pcm_push_tx(struct xtfpga_i2s *i2s) tx_substream = rcu_dereference(i2s->tx_substream); tx_active = tx_substream && snd_pcm_running(tx_substream); if (tx_active) { - unsigned tx_ptr = ACCESS_ONCE(i2s->tx_ptr); + unsigned tx_ptr = READ_ONCE(i2s->tx_ptr); unsigned new_tx_ptr = i2s->tx_fn(i2s, tx_substream->runtime, tx_ptr); @@ -437,7 +437,7 @@ static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ACCESS_ONCE(i2s->tx_ptr) = 0; + WRITE_ONCE(i2s->tx_ptr, 0); rcu_assign_pointer(i2s->tx_substream, substream); xtfpga_pcm_refill_fifo(i2s); break; @@ -459,7 +459,7 @@ static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct xtfpga_i2s *i2s = runtime->private_data; - snd_pcm_uframes_t pos = ACCESS_ONCE(i2s->tx_ptr); + snd_pcm_uframes_t pos = READ_ONCE(i2s->tx_ptr); return pos < runtime->buffer_size ? pos : 0; } diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index b9981e8c0027..b840ff2dcfbb 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -53,7 +53,7 @@ int snd_emux_new(struct snd_emux **remu) emu->max_voices = 0; emu->use_time = 0; - setup_timer(&emu->tlist, snd_emux_timer_callback, (unsigned long)emu); + timer_setup(&emu->tlist, snd_emux_timer_callback, 0); emu->timer_active = 0; *remu = emu; diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index de19e108974a..764ff4bc2089 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -430,7 +430,6 @@ gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, { int voice; unsigned short p1; - short p2; int plong; struct snd_midi_channel *chan; @@ -445,7 +444,6 @@ gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, chan = &port->chset.channels[voice]; p1 = *(unsigned short *) &event[4]; - p2 = *(short *) &event[6]; plong = *(int*) &event[4]; switch (cmd) { diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index 599551b5af44..9fa696b0dbde 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c @@ -202,9 +202,9 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan) * * release the pending note-offs */ -void snd_emux_timer_callback(unsigned long data) +void snd_emux_timer_callback(struct timer_list *t) { - struct snd_emux *emu = (struct snd_emux *) data; + struct snd_emux *emu = from_timer(emu, t, tlist); struct snd_emux_voice *vp; unsigned long flags; int ch, do_again = 0; diff --git a/sound/synth/emux/emux_voice.h b/sound/synth/emux/emux_voice.h index a7073c371bcc..326fa8993d7b 100644 --- a/sound/synth/emux/emux_voice.h +++ b/sound/synth/emux/emux_voice.h @@ -55,7 +55,7 @@ void snd_emux_update_channel(struct snd_emux_port *port, struct snd_midi_channel *chan, int update); void snd_emux_update_port(struct snd_emux_port *port, int update); -void snd_emux_timer_callback(unsigned long data); +void snd_emux_timer_callback(struct timer_list *t); /* emux_effect.c */ #ifdef SNDRV_EMUX_USE_RAW_EFFECT diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index c7641cb50616..17d5e3ee6d73 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -174,11 +174,9 @@ destroy_chip: static void usb6fire_chip_disconnect(struct usb_interface *intf) { struct sfire_chip *chip; - struct snd_card *card; chip = usb_get_intfdata(intf); if (chip) { /* if !chip, fw upload has been performed */ - card = chip->card; chip->intf_count--; if (!chip->intf_count) { mutex_lock(®ister_mutex); diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index 7371e5b06035..d6c8b29fe430 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -108,7 +108,7 @@ static void bcd2000_midi_handle_input(struct bcd2000 *bcd2k, unsigned int payload_length, tocopy; struct snd_rawmidi_substream *midi_receive_substream; - midi_receive_substream = ACCESS_ONCE(bcd2k->midi_receive_substream); + midi_receive_substream = READ_ONCE(bcd2k->midi_receive_substream); if (!midi_receive_substream) return; @@ -139,7 +139,7 @@ static void bcd2000_midi_send(struct bcd2000 *bcd2k) BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE); - midi_out_substream = ACCESS_ONCE(bcd2k->midi_out_substream); + midi_out_substream = READ_ONCE(bcd2k->midi_out_substream); if (!midi_out_substream) return; @@ -342,6 +342,13 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k) bcd2k->midi_out_buf, BUFSIZE, bcd2000_output_complete, bcd2k, 1); + /* sanity checks of EPs before actually submitting */ + if (usb_urb_ep_type_check(bcd2k->midi_in_urb) || + usb_urb_ep_type_check(bcd2k->midi_out_urb)) { + dev_err(&bcd2k->dev->dev, "invalid MIDI EP\n"); + return -EINVAL; + } + bcd2000_init_device(bcd2k); return 0; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index d8409d9ae55b..d55ca48de3ea 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -461,6 +461,13 @@ static int init_card(struct snd_usb_caiaqdev *cdev) cdev->midi_out_buf, EP1_BUFSIZE, snd_usb_caiaq_midi_output_done, cdev); + /* sanity checks of EPs before actually submitting */ + if (usb_urb_ep_type_check(&cdev->ep1_in_urb) || + usb_urb_ep_type_check(&cdev->midi_out_urb)) { + dev_err(dev, "invalid EPs\n"); + return -EINVAL; + } + init_waitqueue_head(&cdev->ep1_wait_queue); init_waitqueue_head(&cdev->prepare_wait_queue); diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 4b3fb91deecd..e883659ea6e7 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -718,6 +718,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) usb_rcvbulkpipe(usb_dev, 0x4), cdev->ep4_in_buf, EP4_BUFSIZE, snd_usb_caiaq_ep4_reply_dispatch, cdev); + ret = usb_urb_ep_type_check(cdev->ep4_in_urb); + if (ret < 0) + goto exit_free_idev; snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); @@ -757,6 +760,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) usb_rcvbulkpipe(usb_dev, 0x4), cdev->ep4_in_buf, EP4_BUFSIZE, snd_usb_caiaq_ep4_reply_dispatch, cdev); + ret = usb_urb_ep_type_check(cdev->ep4_in_urb); + if (ret < 0) + goto exit_free_idev; snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); @@ -802,6 +808,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) usb_rcvbulkpipe(usb_dev, 0x4), cdev->ep4_in_buf, EP4_BUFSIZE, snd_usb_caiaq_ep4_reply_dispatch, cdev); + ret = usb_urb_ep_type_check(cdev->ep4_in_urb); + if (ret < 0) + goto exit_free_idev; snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); break; diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 26dd5f20f149..eb3396ffba4c 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -43,7 +43,7 @@ static struct uac_clock_source_descriptor * while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, cs, UAC2_CLOCK_SOURCE))) { - if (cs->bClockID == clock_id) + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) return cs; } @@ -59,8 +59,11 @@ static struct uac_clock_selector_descriptor * while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, cs, UAC2_CLOCK_SELECTOR))) { - if (cs->bClockID == clock_id) + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) { + if (cs->bLength < 5 + cs->bNrInPins) + return NULL; return cs; + } } return NULL; @@ -75,7 +78,7 @@ static struct uac_clock_multiplier_descriptor * while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, cs, UAC2_CLOCK_MULTIPLIER))) { - if (cs->bClockID == clock_id) + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) return cs; } diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index 175d8d6b7f59..396c317115b1 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -541,6 +541,8 @@ static int hiface_pcm_init_urb(struct pcm_urb *urb, usb_fill_bulk_urb(&urb->instance, chip->dev, usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, PCM_PACKET_SIZE, handler, urb); + if (usb_urb_ep_type_check(&urb->instance)) + return -EINVAL; init_usb_anchor(&urb->submitted); return 0; @@ -599,9 +601,12 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) mutex_init(&rt->stream_mutex); spin_lock_init(&rt->playback.lock); - for (i = 0; i < PCM_N_URBS; i++) - hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, + for (i = 0; i < PCM_N_URBS; i++) { + ret = hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, hiface_pcm_out_urb_handler); + if (ret < 0) + return ret; + } ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm); if (ret < 0) { diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 7c812565f90d..947d6168f24a 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -248,7 +248,7 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) } /* capture operators */ -struct snd_pcm_ops snd_line6_capture_ops = { +const struct snd_pcm_ops snd_line6_capture_ops = { .open = snd_line6_capture_open, .close = snd_line6_capture_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index 890b21bff18c..b67ccc39fd25 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -17,7 +17,7 @@ #include "driver.h" #include "pcm.h" -extern struct snd_pcm_ops snd_line6_capture_ops; +extern const struct snd_pcm_ops snd_line6_capture_ops; extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize); diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index c8f723c3a033..c1376bfdc90b 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -78,6 +78,13 @@ static int line6_start_listen(struct usb_line6 *line6) line6->buffer_listen, LINE6_BUFSIZE_LISTEN, line6_data_received, line6); } + + /* sanity checks of EP before actually submitting */ + if (usb_urb_ep_type_check(line6->urb_listen)) { + dev_err(line6->ifcdev, "invalid control EP\n"); + return -EINVAL; + } + line6->urb_listen->actual_length = 0; err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); return err; @@ -168,26 +175,33 @@ static int line6_send_raw_message_async_part(struct message *msg, } msg->done += bytes; - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval < 0) { - dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", - __func__, retval); - usb_free_urb(urb); - kfree(msg); - return retval; - } + /* sanity checks of EP before actually submitting */ + retval = usb_urb_ep_type_check(urb); + if (retval < 0) + goto error; + + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval < 0) + goto error; return 0; + + error: + dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", + __func__, retval); + usb_free_urb(urb); + kfree(msg); + return retval; } /* Setup and start timer. */ void line6_start_timer(struct timer_list *timer, unsigned long msecs, - void (*function)(unsigned long), unsigned long data) + void (*function)(struct timer_list *t)) { - setup_timer(timer, function, data); + timer->function = function; mod_timer(timer, jiffies + msecs_to_jiffies(msecs)); } EXPORT_SYMBOL_GPL(line6_start_timer); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index dc97895547be..61425597eb61 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -198,8 +198,7 @@ extern int line6_send_sysex_message(struct usb_line6 *line6, extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); extern void line6_start_timer(struct timer_list *timer, unsigned long msecs, - void (*function)(unsigned long), - unsigned long data); + void (*function)(struct timer_list *t)); extern int line6_version_request_async(struct usb_line6 *line6); extern int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, unsigned datalen); diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index 1d3a23b02d68..6d7cde56a355 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -130,16 +130,21 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, transfer_buffer, length, midi_sent, line6, line6->interval); urb->actual_length = 0; - retval = usb_submit_urb(urb, GFP_ATOMIC); + retval = usb_urb_ep_type_check(urb); + if (retval < 0) + goto error; - if (retval < 0) { - dev_err(line6->ifcdev, "usb_submit_urb failed\n"); - usb_free_urb(urb); - return retval; - } + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval < 0) + goto error; ++line6->line6midi->num_active_send_urbs; return 0; + + error: + dev_err(line6->ifcdev, "usb_submit_urb failed\n"); + usb_free_urb(urb); + return retval; } static int line6_midi_output_open(struct snd_rawmidi_substream *substream) diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 812d18191e01..819e9b2d1d6e 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -393,7 +393,7 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream) } /* playback operators */ -struct snd_pcm_ops snd_line6_playback_ops = { +const struct snd_pcm_ops snd_line6_playback_ops = { .open = snd_line6_playback_open, .close = snd_line6_playback_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index 51fce29e8726..d8d3b8a07a72 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -27,7 +27,7 @@ */ #define USE_CLEAR_BUFFER_WORKAROUND 1 -extern struct snd_pcm_ops snd_line6_playback_ops; +extern const struct snd_pcm_ops snd_line6_playback_ops; extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 358224cc5638..020c81818951 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -174,7 +174,7 @@ static const char pod_version_header[] = { }; /* forward declarations: */ -static void pod_startup2(unsigned long data); +static void pod_startup2(struct timer_list *t); static void pod_startup3(struct usb_line6_pod *pod); static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, @@ -286,13 +286,12 @@ static void pod_startup1(struct usb_line6_pod *pod) CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); /* delay startup procedure: */ - line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, - (unsigned long)pod); + line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2); } -static void pod_startup2(unsigned long data) +static void pod_startup2(struct timer_list *t) { - struct usb_line6_pod *pod = (struct usb_line6_pod *)data; + struct usb_line6_pod *pod = from_timer(pod, t, startup_timer); struct usb_line6 *line6 = &pod->line6; CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); @@ -413,7 +412,7 @@ static int pod_init(struct usb_line6 *line6, line6->process_message = line6_pod_process_message; line6->disconnect = line6_pod_disconnect; - init_timer(&pod->startup_timer); + timer_setup(&pod->startup_timer, NULL, 0); INIT_WORK(&pod->startup_work, pod_startup4); /* create sysfs entries: */ diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 451007c27743..36ed9c85c0eb 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -39,7 +39,8 @@ enum { LINE6_PODHD500_1, LINE6_PODX3, LINE6_PODX3LIVE, - LINE6_PODHD500X + LINE6_PODHD500X, + LINE6_PODHDDESKTOP }; struct usb_line6_podhd { @@ -157,7 +158,7 @@ static struct line6_pcm_properties podx3_pcm_properties = { }; static struct usb_driver podhd_driver; -static void podhd_startup_start_workqueue(unsigned long data); +static void podhd_startup_start_workqueue(struct timer_list *t); static void podhd_startup_workqueue(struct work_struct *work); static int podhd_startup_finalize(struct usb_line6_podhd *pod); @@ -207,12 +208,12 @@ static void podhd_startup(struct usb_line6_podhd *pod) /* delay startup procedure: */ line6_start_timer(&pod->startup_timer, PODHD_STARTUP_DELAY, - podhd_startup_start_workqueue, (unsigned long)pod); + podhd_startup_start_workqueue); } -static void podhd_startup_start_workqueue(unsigned long data) +static void podhd_startup_start_workqueue(struct timer_list *t) { - struct usb_line6_podhd *pod = (struct usb_line6_podhd *)data; + struct usb_line6_podhd *pod = from_timer(pod, t, startup_timer); CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_SCHEDULE_WORKQUEUE); @@ -318,7 +319,7 @@ static int podhd_init(struct usb_line6 *line6, line6->disconnect = podhd_disconnect; - init_timer(&pod->startup_timer); + timer_setup(&pod->startup_timer, NULL, 0); INIT_WORK(&pod->startup_work, podhd_startup_workqueue); if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { @@ -379,6 +380,7 @@ static const struct usb_device_id podhd_id_table[] = { { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 }, { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE }, { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X }, + { LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP }, {} }; @@ -465,6 +467,18 @@ static const struct line6_properties podhd_properties_table[] = { .ep_audio_r = 0x86, .ep_audio_w = 0x02, }, + [LINE6_PODHDDESKTOP] = { + .id = "PODHDDESKTOP", + .name = "POD HDDESKTOP", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ctrl_if = 1, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, }; /* diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index ba7975c0d03d..750467fb95db 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -241,9 +241,9 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, return 1; } -static void toneport_start_pcm(unsigned long arg) +static void toneport_start_pcm(struct timer_list *t) { - struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; + struct usb_line6_toneport *toneport = from_timer(toneport, t, timer); struct usb_line6 *line6 = &toneport->line6; line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true); @@ -415,8 +415,7 @@ static int toneport_init(struct usb_line6 *line6, struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; toneport->type = id->driver_info; - setup_timer(&toneport->timer, toneport_start_pcm, - (unsigned long)toneport); + timer_setup(&toneport->timer, toneport_start_pcm, 0); line6->disconnect = line6_toneport_disconnect; diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index 0c4512d0382e..e8c852b2ce35 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -82,9 +82,9 @@ static const char variax_activate[] = { }; /* forward declarations: */ -static void variax_startup2(unsigned long data); -static void variax_startup4(unsigned long data); -static void variax_startup5(unsigned long data); +static void variax_startup2(struct timer_list *t); +static void variax_startup4(struct timer_list *t); +static void variax_startup5(struct timer_list *t); static void variax_activate_async(struct usb_line6_variax *variax, int a) { @@ -106,12 +106,12 @@ static void variax_startup1(struct usb_line6_variax *variax) /* delay startup procedure: */ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2, (unsigned long)variax); + variax_startup2); } -static void variax_startup2(unsigned long data) +static void variax_startup2(struct timer_list *t) { - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6_variax *variax = from_timer(variax, t, startup_timer1); struct usb_line6 *line6 = &variax->line6; /* schedule another startup procedure until startup is complete: */ @@ -120,7 +120,7 @@ static void variax_startup2(unsigned long data) variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2, (unsigned long)variax); + variax_startup2); /* request firmware version: */ line6_version_request_async(line6); @@ -132,12 +132,12 @@ static void variax_startup3(struct usb_line6_variax *variax) /* delay startup procedure: */ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, - variax_startup4, (unsigned long)variax); + variax_startup4); } -static void variax_startup4(unsigned long data) +static void variax_startup4(struct timer_list *t) { - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2); CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_ACTIVATE); @@ -145,12 +145,12 @@ static void variax_startup4(unsigned long data) /* activate device: */ variax_activate_async(variax, 1); line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, - variax_startup5, (unsigned long)variax); + variax_startup5); } -static void variax_startup5(unsigned long data) +static void variax_startup5(struct timer_list *t) { - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2); CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WORKQUEUE); @@ -190,7 +190,7 @@ static void line6_variax_process_message(struct usb_line6 *line6) } else if (memcmp(buf + 1, variax_init_done + 1, sizeof(variax_init_done) - 1) == 0) { /* notify of complete initialization: */ - variax_startup4((unsigned long)variax); + variax_startup4(&variax->startup_timer2); } break; } @@ -222,8 +222,8 @@ static int variax_init(struct usb_line6 *line6, line6->process_message = line6_variax_process_message; line6->disconnect = line6_variax_disconnect; - init_timer(&variax->startup_timer1); - init_timer(&variax->startup_timer2); + timer_setup(&variax->startup_timer1, NULL, 0); + timer_setup(&variax->startup_timer2, NULL, 0); INIT_WORK(&variax->startup_work, variax_startup6); /* initialize USB buffers: */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index a92e2b2a91ec..2c1aaa3292bf 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -352,9 +352,9 @@ static void snd_usbmidi_out_tasklet(unsigned long data) } /* called after transfers had been interrupted due to some USB error */ -static void snd_usbmidi_error_timer(unsigned long data) +static void snd_usbmidi_error_timer(struct timer_list *t) { - struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; + struct snd_usb_midi *umidi = from_timer(umidi, t, error_timer); unsigned int i, j; spin_lock(&umidi->disc_lock); @@ -1282,6 +1282,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, unsigned int pipe; int length; unsigned int i; + int err; rep->in = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -1292,8 +1293,8 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, for (i = 0; i < INPUT_URBS; ++i) { ep->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); if (!ep->urbs[i]) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + err = -ENOMEM; + goto error; } } if (ep_info->in_interval) @@ -1305,8 +1306,8 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, buffer = usb_alloc_coherent(umidi->dev, length, GFP_KERNEL, &ep->urbs[i]->transfer_dma); if (!buffer) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + err = -ENOMEM; + goto error; } if (ep_info->in_interval) usb_fill_int_urb(ep->urbs[i], umidi->dev, @@ -1318,10 +1319,20 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep); ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + err = usb_urb_ep_type_check(ep->urbs[i]); + if (err < 0) { + dev_err(&umidi->dev->dev, "invalid MIDI in EP %x\n", + ep_info->in_ep); + goto error; + } } rep->in = ep; return 0; + + error: + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; } /* @@ -1357,6 +1368,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, unsigned int i; unsigned int pipe; void *buffer; + int err; rep->out = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -1367,8 +1379,8 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, for (i = 0; i < OUTPUT_URBS; ++i) { ep->urbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); if (!ep->urbs[i].urb) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + err = -ENOMEM; + goto error; } ep->urbs[i].ep = ep; } @@ -1406,8 +1418,8 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, ep->max_transfer, GFP_KERNEL, &ep->urbs[i].urb->transfer_dma); if (!buffer) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + err = -ENOMEM; + goto error; } if (ep_info->out_interval) usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, @@ -1419,6 +1431,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i]); + err = usb_urb_ep_type_check(ep->urbs[i].urb); + if (err < 0) { + dev_err(&umidi->dev->dev, "invalid MIDI out EP %x\n", + ep_info->out_ep); + goto error; + } ep->urbs[i].urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } @@ -1437,6 +1455,10 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, rep->out = ep; return 0; + + error: + snd_usbmidi_out_endpoint_delete(ep); + return err; } /* @@ -2347,8 +2369,7 @@ int __snd_usbmidi_create(struct snd_card *card, usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->usb_id = usb_id; - setup_timer(&umidi->error_timer, snd_usbmidi_error_timer, - (unsigned long)umidi); + timer_setup(&umidi->error_timer, snd_usbmidi_error_timer, 0); /* detect the endpoint(s) to use */ memset(endpoints, 0, sizeof(endpoints)); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 91bc8f18791e..0537c6322990 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1469,10 +1469,16 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, __u8 *bmaControls; if (state->mixer->protocol == UAC_VERSION_1) { + if (hdr->bLength < 7) { + usb_audio_err(state->chip, + "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } csize = hdr->bControlSize; - if (!csize) { + if (csize <= 1) { usb_audio_dbg(state->chip, - "unit %u: invalid bControlSize == 0\n", + "unit %u: invalid bControlSize <= 1\n", unitid); return -EINVAL; } @@ -1486,6 +1492,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, } } else { struct uac2_feature_unit_descriptor *ftr = _ftr; + if (hdr->bLength < 6) { + usb_audio_err(state->chip, + "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; @@ -2086,7 +2098,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, const struct usbmix_name_map *map; char **namelist; - if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) { + if (desc->bLength < 5 || !desc->bNrInPins || + desc->bLength < 5 + desc->bNrInPins) { usb_audio_err(state->chip, "invalid SELECTOR UNIT descriptor %d\n", unitid); return -EINVAL; @@ -2330,9 +2343,14 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) { struct usb_mixer_elem_list *list; - for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { + struct usb_mixer_elem_info *info = + (struct usb_mixer_elem_info *)list; + /* invalidate cache, so the value is read from the device */ + info->cached = 0; snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &list->kctl->id); + } } static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 4f5f18f22974..77eecaa4db1f 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1128,30 +1128,24 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) /* devices which do not support reading the sample rate. */ switch (chip->usb_id) { case USB_ID(0x041E, 0x4080): /* Creative Live Cam VF0610 */ - case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ - case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ - case USB_ID(0x045E, 0x076E): /* MS Lifecam HD-5001 */ - case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ - case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ - case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ - case USB_ID(0x047F, 0x02F7): /* Plantronics BT-600 */ - case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */ - case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ - case USB_ID(0x047F, 0xC022): /* Plantronics C310 */ - case USB_ID(0x047F, 0xC02F): /* Plantronics P610 */ - case USB_ID(0x047F, 0xC036): /* Plantronics C520-M */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */ case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */ - case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */ - case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ - case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ return true; } + + /* devices of these vendors don't support reading rate, either */ + switch (USB_ID_VENDOR(chip->usb_id)) { + case 0x045E: /* MS Lifecam */ + case 0x047F: /* Plantronics */ + case 0x1de7: /* Phoenix Audio */ + return true; + } + return false; } @@ -1375,6 +1369,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case 0x199: return SNDRV_PCM_FMTBIT_DSD_U32_LE; case 0x19b: + case 0x203: return SNDRV_PCM_FMTBIT_DSD_U32_BE; default: break; diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index e229abd21652..b0f8979ff2d2 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -56,7 +56,7 @@ check: lb, s->period_size); } -static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, +static int init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, struct urb **urbs, char *transfer, struct usb_device *dev, int pipe) { @@ -77,6 +77,8 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, urb->interval = 1; if (usb_pipeout(pipe)) continue; + if (usb_urb_ep_type_check(urb)) + return -EINVAL; urb->transfer_buffer_length = transfer_length; desc = urb->iso_frame_desc; @@ -87,9 +89,11 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, desc[p].length = maxpacket; } } + + return 0; } -static void init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, +static int init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, struct usb_device *dev, int in_pipe, int out_pipe) { struct usb_stream *s = sk->s; @@ -103,9 +107,12 @@ static void init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL); } - init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe); - init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev, - out_pipe); + if (init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe) || + init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev, + out_pipe)) + return -EINVAL; + + return 0; } @@ -226,7 +233,11 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, else sk->freqn = get_usb_high_speed_rate(sample_rate); - init_urbs(sk, use_packsize, dev, in_pipe, out_pipe); + if (init_urbs(sk, use_packsize, dev, in_pipe, out_pipe) < 0) { + usb_stream_free(sk); + return NULL; + } + sk->s->state = usb_stream_stopped; out: return sk->s; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 4569c0efac0a..0ddf29267d70 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -279,6 +279,9 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); + err = usb_urb_ep_type_check(usX2Y->AS04.urb[i]); + if (err < 0) + break; } return err; } @@ -298,6 +301,8 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y) usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); + if (usb_urb_ep_type_check(usX2Y->In04urb)) + return -EINVAL; return usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index f93b355756e6..345e439aa95b 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -677,6 +677,9 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); } + err = usb_urb_ep_type_check(us->urb[0]); + if (err < 0) + goto cleanup; us->submitted = 0; us->len = NOOF_SETRATE_URBS; usX2Y->US04 = us; |