Update Linux to v5.10.109

Sourced from [1]

[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz

Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 09932cc..7141f73 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SND_MPU401_UART
-        tristate
-        select SND_RAWMIDI
+	tristate
+	select SND_RAWMIDI
 
 config SND_OPL3_LIB
 	tristate
@@ -90,16 +90,17 @@
 	  will be called snd-dummy.
 
 config SND_ALOOP
-        tristate "Generic loopback driver (PCM)"
-        select SND_PCM
-        help
-          Say 'Y' or 'M' to include support for the PCM loopback device.
+	tristate "Generic loopback driver (PCM)"
+	select SND_PCM
+	select SND_TIMER
+	help
+	  Say 'Y' or 'M' to include support for the PCM loopback device.
 	  This module returns played samples back to the user space using
 	  the standard ALSA PCM device. The devices are routed 0->1 and
-          1->0, where first number is the playback PCM device and second
+	  1->0, where first number is the playback PCM device and second
 	  number is the capture device. Module creates two PCM devices and
 	  configured number of substreams (see the pcm_substreams module
-          parameter).
+	  parameter).
 
 	  The loopback device allows time sychronization with an external
 	  timing source using the time shift universal control (+-20%
@@ -142,12 +143,12 @@
 	select SND_RAWMIDI
 	help
 	  The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with 
-          additional SMPTE Timecode capabilities for the parallel port.
+	  additional SMPTE Timecode capabilities for the parallel port.
 
 	  Say 'Y' to include support for this device.
 
 	  To compile this driver as a module, chose 'M' here: the module 
-          will be called snd-mts64.
+	  will be called snd-mts64.
 
 config SND_SERIAL_U16550
 	tristate "UART16550 serial MIDI driver"
@@ -185,18 +186,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-portman2x4.
 
-config SND_ML403_AC97CR
-	tristate "Xilinx ML403 AC97 Controller Reference"
-	depends on XILINX_VIRTEX
-	select SND_AC97_CODEC
-	help
-	  Say Y here to include support for the
-	  opb_ac97_controller_ref_v1_00_a ip core found in Xilinx's ML403
-	  reference design.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-ml403_ac97cr.
-
 config SND_AC97_POWER_SAVE
 	bool "AC97 Power-Saving Mode"
 	depends on SND_AC97_CODEC
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index 615558a..c0fe4ec 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -11,7 +11,6 @@
 snd-portman2x4-objs := portman2x4.o
 snd-serial-u16550-objs := serial-u16550.o
 snd-virmidi-objs := virmidi.o
-snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
@@ -21,6 +20,5 @@
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
 obj-$(CONFIG_SND_MTS64) += snd-mts64.o
 obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
-obj-$(CONFIG_SND_ML403_AC97CR) += snd-ml403-ac97cr.o
 
 obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ pcsp/
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 452b9ea..2c5f7e9 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -28,6 +28,7 @@
 #include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/initval.h>
+#include <sound/timer.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("A loopback soundcard");
@@ -41,6 +42,7 @@
 static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
 static int pcm_notify[SNDRV_CARDS];
+static char *timer_source[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
@@ -52,11 +54,48 @@
 MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
 module_param_array(pcm_notify, int, NULL, 0444);
 MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
+module_param_array(timer_source, charp, NULL, 0444);
+MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default].");
 
 #define NO_PITCH 100000
 
+#define CABLE_VALID_PLAYBACK	BIT(SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE	BIT(SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH	(CABLE_VALID_PLAYBACK | CABLE_VALID_CAPTURE)
+
+struct loopback_cable;
 struct loopback_pcm;
 
+struct loopback_ops {
+	/* optional
+	 * call in loopback->cable_lock
+	 */
+	int (*open)(struct loopback_pcm *dpcm);
+	/* required
+	 * call in cable->lock
+	 */
+	int (*start)(struct loopback_pcm *dpcm);
+	/* required
+	 * call in cable->lock
+	 */
+	int (*stop)(struct loopback_pcm *dpcm);
+	/* optional */
+	int (*stop_sync)(struct loopback_pcm *dpcm);
+	/* optional */
+	int (*close_substream)(struct loopback_pcm *dpcm);
+	/* optional
+	 * call in loopback->cable_lock
+	 */
+	int (*close_cable)(struct loopback_pcm *dpcm);
+	/* optional
+	 * call in cable->lock
+	 */
+	unsigned int (*pos_update)(struct loopback_cable *cable);
+	/* optional */
+	void (*dpcm_info)(struct loopback_pcm *dpcm,
+			  struct snd_info_buffer *buffer);
+};
+
 struct loopback_cable {
 	spinlock_t lock;
 	struct loopback_pcm *streams[2];
@@ -65,12 +104,21 @@
 	unsigned int valid;
 	unsigned int running;
 	unsigned int pause;
+	/* timer specific */
+	struct loopback_ops *ops;
+	/* If sound timer is used */
+	struct {
+		int stream;
+		struct snd_timer_id id;
+		struct work_struct event_work;
+		struct snd_timer_instance *instance;
+	} snd_timer;
 };
 
 struct loopback_setup {
 	unsigned int notify: 1;
 	unsigned int rate_shift;
-	unsigned int format;
+	snd_pcm_format_t format;
 	unsigned int rate;
 	unsigned int channels;
 	struct snd_ctl_elem_id active_id;
@@ -85,6 +133,7 @@
 	struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
 	struct snd_pcm *pcm[2];
 	struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
+	const char *timer_source;
 };
 
 struct loopback_pcm {
@@ -102,10 +151,13 @@
 	/* flags */
 	unsigned int period_update_pending :1;
 	/* timer stuff */
-	unsigned int irq_pos;		/* fractional IRQ position */
-	unsigned int period_size_frac;
+	unsigned int irq_pos;		/* fractional IRQ position in jiffies
+					 * ticks
+					 */
+	unsigned int period_size_frac;	/* period size in jiffies ticks */
 	unsigned int last_drift;
 	unsigned long last_jiffies;
+	/* If jiffies timer is used */
 	struct timer_list timer;
 };
 
@@ -153,7 +205,7 @@
 }
 
 /* call in cable->lock */
-static void loopback_timer_start(struct loopback_pcm *dpcm)
+static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm)
 {
 	unsigned long tick;
 	unsigned int rate_shift = get_rate_shift(dpcm);
@@ -169,23 +221,102 @@
 	tick = dpcm->period_size_frac - dpcm->irq_pos;
 	tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
 	mod_timer(&dpcm->timer, jiffies + tick);
+
+	return 0;
 }
 
 /* call in cable->lock */
-static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
+static int loopback_snd_timer_start(struct loopback_pcm *dpcm)
+{
+	struct loopback_cable *cable = dpcm->cable;
+	int err;
+
+	/* Loopback device has to use same period as timer card. Therefore
+	 * wake up for each snd_pcm_period_elapsed() call of timer card.
+	 */
+	err = snd_timer_start(cable->snd_timer.instance, 1);
+	if (err < 0) {
+		/* do not report error if trying to start but already
+		 * running. For example called by opposite substream
+		 * of the same cable
+		 */
+		if (err == -EBUSY)
+			return 0;
+
+		pcm_err(dpcm->substream->pcm,
+			"snd_timer_start(%d,%d,%d) failed with %d",
+			cable->snd_timer.id.card,
+			cable->snd_timer.id.device,
+			cable->snd_timer.id.subdevice,
+			err);
+	}
+
+	return err;
+}
+
+/* call in cable->lock */
+static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm)
 {
 	del_timer(&dpcm->timer);
 	dpcm->timer.expires = 0;
+
+	return 0;
 }
 
-static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm)
+/* call in cable->lock */
+static int loopback_snd_timer_stop(struct loopback_pcm *dpcm)
+{
+	struct loopback_cable *cable = dpcm->cable;
+	int err;
+
+	/* only stop if both devices (playback and capture) are not running */
+	if (cable->running ^ cable->pause)
+		return 0;
+
+	err = snd_timer_stop(cable->snd_timer.instance);
+	if (err < 0) {
+		pcm_err(dpcm->substream->pcm,
+			"snd_timer_stop(%d,%d,%d) failed with %d",
+			cable->snd_timer.id.card,
+			cable->snd_timer.id.device,
+			cable->snd_timer.id.subdevice,
+			err);
+	}
+
+	return err;
+}
+
+static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm)
 {
 	del_timer_sync(&dpcm->timer);
+
+	return 0;
 }
 
-#define CABLE_VALID_PLAYBACK	(1 << SNDRV_PCM_STREAM_PLAYBACK)
-#define CABLE_VALID_CAPTURE	(1 << SNDRV_PCM_STREAM_CAPTURE)
-#define CABLE_VALID_BOTH	(CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+/* call in loopback->cable_lock */
+static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
+{
+	struct loopback_cable *cable = dpcm->cable;
+
+	/* snd_timer was not opened */
+	if (!cable->snd_timer.instance)
+		return 0;
+
+	/* will only be called from free_cable() when other stream was
+	 * already closed. Other stream cannot be reopened as long as
+	 * loopback->cable_lock is locked. Therefore no need to lock
+	 * cable->lock;
+	 */
+	snd_timer_close(cable->snd_timer.instance);
+
+	/* wait till drain work has finished if requested */
+	cancel_work_sync(&cable->snd_timer.event_work);
+
+	snd_timer_instance_free(cable->snd_timer.instance);
+	memset(&cable->snd_timer, 0, sizeof(cable->snd_timer));
+
+	return 0;
+}
 
 static int loopback_check_format(struct loopback_cable *cable, int stream)
 {
@@ -249,7 +380,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct loopback_pcm *dpcm = runtime->private_data;
 	struct loopback_cable *cable = dpcm->cable;
-	int err, stream = 1 << substream->stream;
+	int err = 0, stream = 1 << substream->stream;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -262,7 +393,7 @@
 		spin_lock(&cable->lock);	
 		cable->running |= stream;
 		cable->pause &= ~stream;
-		loopback_timer_start(dpcm);
+		err = cable->ops->start(dpcm);
 		spin_unlock(&cable->lock);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			loopback_active_notify(dpcm);
@@ -271,7 +402,7 @@
 		spin_lock(&cable->lock);	
 		cable->running &= ~stream;
 		cable->pause &= ~stream;
-		loopback_timer_stop(dpcm);
+		err = cable->ops->stop(dpcm);
 		spin_unlock(&cable->lock);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			loopback_active_notify(dpcm);
@@ -280,7 +411,7 @@
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		spin_lock(&cable->lock);	
 		cable->pause |= stream;
-		loopback_timer_stop(dpcm);
+		err = cable->ops->stop(dpcm);
 		spin_unlock(&cable->lock);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			loopback_active_notify(dpcm);
@@ -290,7 +421,7 @@
 		spin_lock(&cable->lock);
 		dpcm->last_jiffies = jiffies;
 		cable->pause &= ~stream;
-		loopback_timer_start(dpcm);
+		err = cable->ops->start(dpcm);
 		spin_unlock(&cable->lock);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			loopback_active_notify(dpcm);
@@ -298,7 +429,7 @@
 	default:
 		return -EINVAL;
 	}
-	return 0;
+	return err;
 }
 
 static void params_change(struct snd_pcm_substream *substream)
@@ -312,6 +443,13 @@
 	cable->hw.rate_max = runtime->rate;
 	cable->hw.channels_min = runtime->channels;
 	cable->hw.channels_max = runtime->channels;
+
+	if (cable->snd_timer.instance) {
+		cable->hw.period_bytes_min =
+				frames_to_bytes(runtime, runtime->period_size);
+		cable->hw.period_bytes_max = cable->hw.period_bytes_min;
+	}
+
 }
 
 static int loopback_prepare(struct snd_pcm_substream *substream)
@@ -319,9 +457,13 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct loopback_pcm *dpcm = runtime->private_data;
 	struct loopback_cable *cable = dpcm->cable;
-	int bps, salign;
+	int err, bps, salign;
 
-	loopback_timer_stop_sync(dpcm);
+	if (cable->ops->stop_sync) {
+		err = cable->ops->stop_sync(dpcm);
+		if (err < 0)
+			return err;
+	}
 
 	salign = (snd_pcm_format_physical_width(runtime->format) *
 						runtime->channels) / 8;
@@ -457,7 +599,8 @@
 }
 
 /* call in cable->lock */
-static unsigned int loopback_pos_update(struct loopback_cable *cable)
+static unsigned int loopback_jiffies_timer_pos_update
+		(struct loopback_cable *cable)
 {
 	struct loopback_pcm *dpcm_play =
 			cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -510,14 +653,15 @@
 	return running;
 }
 
-static void loopback_timer_function(struct timer_list *t)
+static void loopback_jiffies_timer_function(struct timer_list *t)
 {
 	struct loopback_pcm *dpcm = from_timer(dpcm, t, timer);
 	unsigned long flags;
 
 	spin_lock_irqsave(&dpcm->cable->lock, flags);
-	if (loopback_pos_update(dpcm->cable) & (1 << dpcm->substream->stream)) {
-		loopback_timer_start(dpcm);
+	if (loopback_jiffies_timer_pos_update(dpcm->cable) &
+			(1 << dpcm->substream->stream)) {
+		loopback_jiffies_timer_start(dpcm);
 		if (dpcm->period_update_pending) {
 			dpcm->period_update_pending = 0;
 			spin_unlock_irqrestore(&dpcm->cable->lock, flags);
@@ -529,6 +673,193 @@
 	spin_unlock_irqrestore(&dpcm->cable->lock, flags);
 }
 
+/* call in cable->lock */
+static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime,
+					       unsigned long resolution)
+{
+	if (resolution != runtime->timer_resolution) {
+		struct loopback_pcm *dpcm = runtime->private_data;
+		struct loopback_cable *cable = dpcm->cable;
+		/* Worst case estimation of possible values for resolution
+		 * resolution <= (512 * 1024) frames / 8kHz in nsec
+		 * resolution <= 65.536.000.000 nsec
+		 *
+		 * period_size <= 65.536.000.000 nsec / 1000nsec/usec * 192kHz +
+		 *  500.000
+		 * period_size <= 12.582.912.000.000  <64bit
+		 *  / 1.000.000 usec/sec
+		 */
+		snd_pcm_uframes_t period_size_usec =
+				resolution / 1000 * runtime->rate;
+		/* round to nearest sample rate */
+		snd_pcm_uframes_t period_size =
+				(period_size_usec + 500 * 1000) / (1000 * 1000);
+
+		pcm_err(dpcm->substream->pcm,
+			"Period size (%lu frames) of loopback device is not corresponding to timer resolution (%lu nsec = %lu frames) of card timer %d,%d,%d. Use period size of %lu frames for loopback device.",
+			runtime->period_size, resolution, period_size,
+			cable->snd_timer.id.card,
+			cable->snd_timer.id.device,
+			cable->snd_timer.id.subdevice,
+			period_size);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable,
+					      int event,
+					      unsigned long resolution)
+{
+	struct loopback_pcm *dpcm_play, *dpcm_capt;
+	struct snd_pcm_substream *substream_play, *substream_capt;
+	struct snd_pcm_runtime *valid_runtime;
+	unsigned int running, elapsed_bytes;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cable->lock, flags);
+	running = cable->running ^ cable->pause;
+	/* no need to do anything if no stream is running */
+	if (!running) {
+		spin_unlock_irqrestore(&cable->lock, flags);
+		return;
+	}
+
+	dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+	dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+
+	if (event == SNDRV_TIMER_EVENT_MSTOP) {
+		if (!dpcm_play ||
+		    dpcm_play->substream->runtime->status->state !=
+				SNDRV_PCM_STATE_DRAINING) {
+			spin_unlock_irqrestore(&cable->lock, flags);
+			return;
+		}
+	}
+
+	substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+			dpcm_play->substream : NULL;
+	substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ?
+			dpcm_capt->substream : NULL;
+	valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+				dpcm_play->substream->runtime :
+				dpcm_capt->substream->runtime;
+
+	/* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */
+	if (event == SNDRV_TIMER_EVENT_TICK) {
+		/* The hardware rules guarantee that playback and capture period
+		 * are the same. Therefore only one device has to be checked
+		 * here.
+		 */
+		if (loopback_snd_timer_check_resolution(valid_runtime,
+							resolution) < 0) {
+			spin_unlock_irqrestore(&cable->lock, flags);
+			if (substream_play)
+				snd_pcm_stop_xrun(substream_play);
+			if (substream_capt)
+				snd_pcm_stop_xrun(substream_capt);
+			return;
+		}
+	}
+
+	elapsed_bytes = frames_to_bytes(valid_runtime,
+					valid_runtime->period_size);
+	/* The same timer interrupt is used for playback and capture device */
+	if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
+	    (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) {
+		copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes);
+		bytepos_finish(dpcm_play, elapsed_bytes);
+		bytepos_finish(dpcm_capt, elapsed_bytes);
+	} else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+		bytepos_finish(dpcm_play, elapsed_bytes);
+	} else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+		clear_capture_buf(dpcm_capt, elapsed_bytes);
+		bytepos_finish(dpcm_capt, elapsed_bytes);
+	}
+	spin_unlock_irqrestore(&cable->lock, flags);
+
+	if (substream_play)
+		snd_pcm_period_elapsed(substream_play);
+	if (substream_capt)
+		snd_pcm_period_elapsed(substream_capt);
+}
+
+static void loopback_snd_timer_function(struct snd_timer_instance *timeri,
+					unsigned long resolution,
+					unsigned long ticks)
+{
+	struct loopback_cable *cable = timeri->callback_data;
+
+	loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_TICK,
+					  resolution);
+}
+
+static void loopback_snd_timer_work(struct work_struct *work)
+{
+	struct loopback_cable *cable;
+
+	cable = container_of(work, struct loopback_cable, snd_timer.event_work);
+	loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0);
+}
+
+static void loopback_snd_timer_event(struct snd_timer_instance *timeri,
+				     int event,
+				     struct timespec64 *tstamp,
+				     unsigned long resolution)
+{
+	/* Do not lock cable->lock here because timer->lock is already hold.
+	 * There are other functions which first lock cable->lock and than
+	 * timer->lock e.g.
+	 * loopback_trigger()
+	 * spin_lock(&cable->lock)
+	 * loopback_snd_timer_start()
+	 * snd_timer_start()
+	 * spin_lock(&timer->lock)
+	 * Therefore when using the oposit order of locks here it could result
+	 * in a deadlock.
+	 */
+
+	if (event == SNDRV_TIMER_EVENT_MSTOP) {
+		struct loopback_cable *cable = timeri->callback_data;
+
+		/* sound card of the timer was stopped. Therefore there will not
+		 * be any further timer callbacks. Due to this forward audio
+		 * data from here if in draining state. When still in running
+		 * state the streaming will be aborted by the usual timeout. It
+		 * should not be aborted here because may be the timer sound
+		 * card does only a recovery and the timer is back soon.
+		 * This work triggers loopback_snd_timer_work()
+		 */
+		schedule_work(&cable->snd_timer.event_work);
+	}
+}
+
+static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm,
+					     struct snd_info_buffer *buffer)
+{
+	snd_iprintf(buffer, "    update_pending:\t%u\n",
+		    dpcm->period_update_pending);
+	snd_iprintf(buffer, "    irq_pos:\t\t%u\n", dpcm->irq_pos);
+	snd_iprintf(buffer, "    period_frac:\t%u\n", dpcm->period_size_frac);
+	snd_iprintf(buffer, "    last_jiffies:\t%lu (%lu)\n",
+		    dpcm->last_jiffies, jiffies);
+	snd_iprintf(buffer, "    timer_expires:\t%lu\n", dpcm->timer.expires);
+}
+
+static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
+					 struct snd_info_buffer *buffer)
+{
+	struct loopback_cable *cable = dpcm->cable;
+
+	snd_iprintf(buffer, "    sound timer:\thw:%d,%d,%d\n",
+		    cable->snd_timer.id.card,
+		    cable->snd_timer.id.device,
+		    cable->snd_timer.id.subdevice);
+	snd_iprintf(buffer, "    timer open:\t\t%s\n",
+		    (cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ?
+			    "capture" : "playback");
+}
+
 static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -536,7 +867,8 @@
 	snd_pcm_uframes_t pos;
 
 	spin_lock(&dpcm->cable->lock);
-	loopback_pos_update(dpcm->cable);
+	if (dpcm->cable->ops->pos_update)
+		dpcm->cable->ops->pos_update(dpcm->cable);
 	pos = dpcm->buf_pos;
 	spin_unlock(&dpcm->cable->lock);
 	return bytes_to_frames(runtime, pos);
@@ -573,13 +905,6 @@
 	kfree(dpcm);
 }
 
-static int loopback_hw_params(struct snd_pcm_substream *substream,
-			      struct snd_pcm_hw_params *params)
-{
-	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
-						params_buffer_bytes(params));
-}
-
 static int loopback_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -589,7 +914,7 @@
 	mutex_lock(&dpcm->loopback->cable_lock);
 	cable->valid &= ~(1 << substream->stream);
 	mutex_unlock(&dpcm->loopback->cable_lock);
-	return snd_pcm_lib_free_vmalloc_buffer(substream);
+	return 0;
 }
 
 static unsigned int get_cable_index(struct snd_pcm_substream *substream)
@@ -647,6 +972,23 @@
 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
 
+static int rule_period_bytes(struct snd_pcm_hw_params *params,
+			     struct snd_pcm_hw_rule *rule)
+{
+	struct loopback_pcm *dpcm = rule->private;
+	struct loopback_cable *cable = dpcm->cable;
+	struct snd_interval t;
+
+	mutex_lock(&dpcm->loopback->cable_lock);
+	t.min = cable->hw.period_bytes_min;
+	t.max = cable->hw.period_bytes_max;
+	mutex_unlock(&dpcm->loopback->cable_lock);
+	t.openmin = 0;
+	t.openmax = 0;
+	t.integer = 0;
+	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
 static void free_cable(struct snd_pcm_substream *substream)
 {
 	struct loopback *loopback = substream->private_data;
@@ -662,12 +1004,182 @@
 		cable->streams[substream->stream] = NULL;
 		spin_unlock_irq(&cable->lock);
 	} else {
+		struct loopback_pcm *dpcm = substream->runtime->private_data;
+
+		if (cable->ops && cable->ops->close_cable && dpcm)
+			cable->ops->close_cable(dpcm);
 		/* free the cable */
 		loopback->cables[substream->number][dev] = NULL;
 		kfree(cable);
 	}
 }
 
+static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
+{
+	timer_setup(&dpcm->timer, loopback_jiffies_timer_function, 0);
+
+	return 0;
+}
+
+static struct loopback_ops loopback_jiffies_timer_ops = {
+	.open = loopback_jiffies_timer_open,
+	.start = loopback_jiffies_timer_start,
+	.stop = loopback_jiffies_timer_stop,
+	.stop_sync = loopback_jiffies_timer_stop_sync,
+	.close_substream = loopback_jiffies_timer_stop_sync,
+	.pos_update = loopback_jiffies_timer_pos_update,
+	.dpcm_info = loopback_jiffies_timer_dpcm_info,
+};
+
+static int loopback_parse_timer_id(const char *str,
+				   struct snd_timer_id *tid)
+{
+	/* [<pref>:](<card name>|<card idx>)[{.,}<dev idx>[{.,}<subdev idx>]] */
+	const char * const sep_dev = ".,";
+	const char * const sep_pref = ":";
+	const char *name = str;
+	char *sep, save = '\0';
+	int card_idx = 0, dev = 0, subdev = 0;
+	int err;
+
+	sep = strpbrk(str, sep_pref);
+	if (sep)
+		name = sep + 1;
+	sep = strpbrk(name, sep_dev);
+	if (sep) {
+		save = *sep;
+		*sep = '\0';
+	}
+	err = kstrtoint(name, 0, &card_idx);
+	if (err == -EINVAL) {
+		/* Must be the name, not number */
+		for (card_idx = 0; card_idx < snd_ecards_limit; card_idx++) {
+			struct snd_card *card = snd_card_ref(card_idx);
+
+			if (card) {
+				if (!strcmp(card->id, name))
+					err = 0;
+				snd_card_unref(card);
+			}
+			if (!err)
+				break;
+		}
+	}
+	if (sep) {
+		*sep = save;
+		if (!err) {
+			char *sep2, save2 = '\0';
+
+			sep2 = strpbrk(sep + 1, sep_dev);
+			if (sep2) {
+				save2 = *sep2;
+				*sep2 = '\0';
+			}
+			err = kstrtoint(sep + 1, 0, &dev);
+			if (sep2) {
+				*sep2 = save2;
+				if (!err)
+					err = kstrtoint(sep2 + 1, 0, &subdev);
+			}
+		}
+	}
+	if (!err && tid) {
+		tid->card = card_idx;
+		tid->device = dev;
+		tid->subdevice = subdev;
+	}
+	return err;
+}
+
+/* call in loopback->cable_lock */
+static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
+{
+	int err = 0;
+	struct snd_timer_id tid = {
+		.dev_class = SNDRV_TIMER_CLASS_PCM,
+		.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION,
+	};
+	struct snd_timer_instance *timeri;
+	struct loopback_cable *cable = dpcm->cable;
+
+	/* check if timer was already opened. It is only opened once
+	 * per playback and capture subdevice (aka cable).
+	 */
+	if (cable->snd_timer.instance)
+		goto exit;
+
+	err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid);
+	if (err < 0) {
+		pcm_err(dpcm->substream->pcm,
+			"Parsing timer source \'%s\' failed with %d",
+			dpcm->loopback->timer_source, err);
+		goto exit;
+	}
+
+	cable->snd_timer.stream = dpcm->substream->stream;
+	cable->snd_timer.id = tid;
+
+	timeri = snd_timer_instance_new(dpcm->loopback->card->id);
+	if (!timeri) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	/* The callback has to be called from another work. If
+	 * SNDRV_TIMER_IFLG_FAST is specified it will be called from the
+	 * snd_pcm_period_elapsed() call of the selected sound card.
+	 * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave().
+	 * Due to our callback loopback_snd_timer_function() also calls
+	 * snd_pcm_period_elapsed() which calls snd_pcm_stream_lock_irqsave().
+	 * This would end up in a dead lock.
+	 */
+	timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
+	timeri->callback = loopback_snd_timer_function;
+	timeri->callback_data = (void *)cable;
+	timeri->ccallback = loopback_snd_timer_event;
+
+	/* initialise a work used for draining */
+	INIT_WORK(&cable->snd_timer.event_work, loopback_snd_timer_work);
+
+	/* The mutex loopback->cable_lock is kept locked.
+	 * Therefore snd_timer_open() cannot be called a second time
+	 * by the other device of the same cable.
+	 * Therefore the following issue cannot happen:
+	 * [proc1] Call loopback_timer_open() ->
+	 *	   Unlock cable->lock for snd_timer_close/open() call
+	 * [proc2] Call loopback_timer_open() -> snd_timer_open(),
+	 *	   snd_timer_start()
+	 * [proc1] Call snd_timer_open() and overwrite running timer
+	 *	   instance
+	 */
+	err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid);
+	if (err < 0) {
+		pcm_err(dpcm->substream->pcm,
+			"snd_timer_open (%d,%d,%d) failed with %d",
+			cable->snd_timer.id.card,
+			cable->snd_timer.id.device,
+			cable->snd_timer.id.subdevice,
+			err);
+		snd_timer_instance_free(timeri);
+		goto exit;
+	}
+
+	cable->snd_timer.instance = timeri;
+
+exit:
+	return err;
+}
+
+/* stop_sync() is not required for sound timer because it does not need to be
+ * restarted in loopback_prepare() on Xrun recovery
+ */
+static struct loopback_ops loopback_snd_timer_ops = {
+	.open = loopback_snd_timer_open,
+	.start = loopback_snd_timer_start,
+	.stop = loopback_snd_timer_stop,
+	.close_cable = loopback_snd_timer_close_cable,
+	.dpcm_info = loopback_snd_timer_dpcm_info,
+};
+
 static int loopback_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -685,7 +1197,6 @@
 	}
 	dpcm->loopback = loopback;
 	dpcm->substream = substream;
-	timer_setup(&dpcm->timer, loopback_timer_function, 0);
 
 	cable = loopback->cables[substream->number][dev];
 	if (!cable) {
@@ -696,9 +1207,20 @@
 		}
 		spin_lock_init(&cable->lock);
 		cable->hw = loopback_pcm_hardware;
+		if (loopback->timer_source)
+			cable->ops = &loopback_snd_timer_ops;
+		else
+			cable->ops = &loopback_jiffies_timer_ops;
 		loopback->cables[substream->number][dev] = cable;
 	}
 	dpcm->cable = cable;
+	runtime->private_data = dpcm;
+
+	if (cable->ops->open) {
+		err = cable->ops->open(dpcm);
+		if (err < 0)
+			goto unlock;
+	}
 
 	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 
@@ -724,7 +1246,22 @@
 	if (err < 0)
 		goto unlock;
 
-	runtime->private_data = dpcm;
+	/* In case of sound timer the period time of both devices of the same
+	 * loop has to be the same.
+	 * This rule only takes effect if a sound timer was chosen
+	 */
+	if (cable->snd_timer.instance) {
+		err = snd_pcm_hw_rule_add(runtime, 0,
+					  SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+					  rule_period_bytes, dpcm,
+					  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
+		if (err < 0)
+			goto unlock;
+	}
+
+	/* loopback_runtime_free() has not to be called if kfree(dpcm) was
+	 * already called here. Otherwise it will end up with a double free.
+	 */
 	runtime->private_free = loopback_runtime_free;
 	if (get_notify(dpcm))
 		runtime->hw = loopback_pcm_hardware;
@@ -748,24 +1285,23 @@
 {
 	struct loopback *loopback = substream->private_data;
 	struct loopback_pcm *dpcm = substream->runtime->private_data;
+	int err = 0;
 
-	loopback_timer_stop_sync(dpcm);
+	if (dpcm->cable->ops->close_substream)
+		err = dpcm->cable->ops->close_substream(dpcm);
 	mutex_lock(&loopback->cable_lock);
 	free_cable(substream);
 	mutex_unlock(&loopback->cable_lock);
-	return 0;
+	return err;
 }
 
 static const struct snd_pcm_ops loopback_pcm_ops = {
 	.open =		loopback_open,
 	.close =	loopback_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	loopback_hw_params,
 	.hw_free =	loopback_hw_free,
 	.prepare =	loopback_prepare,
 	.trigger =	loopback_trigger,
 	.pointer =	loopback_pointer,
-	.page =		snd_pcm_lib_get_vmalloc_page,
 };
 
 static int loopback_pcm_new(struct loopback *loopback,
@@ -780,6 +1316,7 @@
 		return err;
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops);
+	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
 
 	pcm->private_data = loopback;
 	pcm->info_flags = 0;
@@ -894,7 +1431,7 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
+	uinfo->value.integer.max = (__force int)SNDRV_PCM_FORMAT_LAST;
 	uinfo->value.integer.step = 1;
 	return 0;
 }                                  
@@ -905,7 +1442,7 @@
 	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
 	
 	ucontrol->value.integer.value[0] =
-		loopback->setup[kcontrol->id.subdevice]
+		(__force int)loopback->setup[kcontrol->id.subdevice]
 			       [kcontrol->id.device].format;
 	return 0;
 }
@@ -958,7 +1495,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new loopback_controls[]  = {
+static const struct snd_kcontrol_new loopback_controls[]  = {
 {
 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
 	.name =         "PCM Rate Shift 100000",
@@ -1081,13 +1618,8 @@
 	snd_iprintf(buffer, "    bytes_per_sec:\t%u\n", dpcm->pcm_bps);
 	snd_iprintf(buffer, "    sample_align:\t%u\n", dpcm->pcm_salign);
 	snd_iprintf(buffer, "    rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
-	snd_iprintf(buffer, "    update_pending:\t%u\n",
-						dpcm->period_update_pending);
-	snd_iprintf(buffer, "    irq_pos:\t\t%u\n", dpcm->irq_pos);
-	snd_iprintf(buffer, "    period_frac:\t%u\n", dpcm->period_size_frac);
-	snd_iprintf(buffer, "    last_jiffies:\t%lu (%lu)\n",
-					dpcm->last_jiffies, jiffies);
-	snd_iprintf(buffer, "    timer_expires:\t%lu\n", dpcm->timer.expires);
+	if (dpcm->cable->ops->dpcm_info)
+		dpcm->cable->ops->dpcm_info(dpcm, buffer);
 }
 
 static void print_substream_info(struct snd_info_buffer *buffer,
@@ -1123,7 +1655,7 @@
 	mutex_unlock(&loopback->cable_lock);
 }
 
-static int loopback_proc_new(struct loopback *loopback, int cidx)
+static int loopback_cable_proc_new(struct loopback *loopback, int cidx)
 {
 	char name[32];
 
@@ -1132,6 +1664,48 @@
 				    print_cable_info);
 }
 
+static void loopback_set_timer_source(struct loopback *loopback,
+				      const char *value)
+{
+	if (loopback->timer_source) {
+		devm_kfree(loopback->card->dev, loopback->timer_source);
+		loopback->timer_source = NULL;
+	}
+	if (value && *value)
+		loopback->timer_source = devm_kstrdup(loopback->card->dev,
+						      value, GFP_KERNEL);
+}
+
+static void print_timer_source_info(struct snd_info_entry *entry,
+				    struct snd_info_buffer *buffer)
+{
+	struct loopback *loopback = entry->private_data;
+
+	mutex_lock(&loopback->cable_lock);
+	snd_iprintf(buffer, "%s\n",
+		    loopback->timer_source ? loopback->timer_source : "");
+	mutex_unlock(&loopback->cable_lock);
+}
+
+static void change_timer_source_info(struct snd_info_entry *entry,
+				     struct snd_info_buffer *buffer)
+{
+	struct loopback *loopback = entry->private_data;
+	char line[64];
+
+	mutex_lock(&loopback->cable_lock);
+	if (!snd_info_get_line(buffer, line, sizeof(line)))
+		loopback_set_timer_source(loopback, strim(line));
+	mutex_unlock(&loopback->cable_lock);
+}
+
+static int loopback_timer_source_proc_new(struct loopback *loopback)
+{
+	return snd_card_rw_proc_new(loopback->card, "timer_source", loopback,
+				    print_timer_source_info,
+				    change_timer_source_info);
+}
+
 static int loopback_probe(struct platform_device *devptr)
 {
 	struct snd_card *card;
@@ -1151,6 +1725,8 @@
 		pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
 	
 	loopback->card = card;
+	loopback_set_timer_source(loopback, timer_source[dev]);
+
 	mutex_init(&loopback->cable_lock);
 
 	err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
@@ -1162,8 +1738,9 @@
 	err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
 	if (err < 0)
 		goto __nodev;
-	loopback_proc_new(loopback, 0);
-	loopback_proc_new(loopback, 1);
+	loopback_cable_proc_new(loopback, 0);
+	loopback_cable_proc_new(loopback, 1);
+	loopback_timer_source_proc_new(loopback);
 	strcpy(card->driver, "Loopback");
 	strcpy(card->shortname, "Loopback");
 	sprintf(card->longname, "Loopback %i", dev + 1);
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index b61ba03..b5486de 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -117,7 +117,7 @@
 
 struct snd_dummy {
 	struct snd_card *card;
-	struct dummy_model *model;
+	const struct dummy_model *model;
 	struct snd_pcm *pcm;
 	struct snd_pcm_hardware pcm_hw;
 	spinlock_t mixer_lock;
@@ -144,13 +144,13 @@
 	return 0;
 }
 
-static struct dummy_model model_emu10k1 = {
+static const struct dummy_model model_emu10k1 = {
 	.name = "emu10k1",
 	.playback_constraints = emu10k1_playback_constraints,
 	.buffer_bytes_max = 128 * 1024,
 };
 
-static struct dummy_model model_rme9652 = {
+static const struct dummy_model model_rme9652 = {
 	.name = "rme9652",
 	.buffer_bytes_max = 26 * 64 * 1024,
 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -160,7 +160,7 @@
 	.periods_max = 2,
 };
 
-static struct dummy_model model_ice1712 = {
+static const struct dummy_model model_ice1712 = {
 	.name = "ice1712",
 	.buffer_bytes_max = 256 * 1024,
 	.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -170,7 +170,7 @@
 	.periods_max = 1024,
 };
 
-static struct dummy_model model_uda1341 = {
+static const struct dummy_model model_uda1341 = {
 	.name = "uda1341",
 	.buffer_bytes_max = 16380,
 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -180,7 +180,7 @@
 	.periods_max = 255,
 };
 
-static struct dummy_model model_ac97 = {
+static const struct dummy_model model_ac97 = {
 	.name = "ac97",
 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	.channels_min = 2,
@@ -190,7 +190,7 @@
 	.rate_max = 48000,
 };
 
-static struct dummy_model model_ca0106 = {
+static const struct dummy_model model_ca0106 = {
 	.name = "ca0106",
 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	.buffer_bytes_max = ((65536-64)*8),
@@ -204,7 +204,7 @@
 	.rate_max = 192000,
 };
 
-static struct dummy_model *dummy_models[] = {
+static const struct dummy_model *dummy_models[] = {
 	&model_emu10k1,
 	&model_rme9652,
 	&model_ice1712,
@@ -529,21 +529,13 @@
 		substream->runtime->dma_bytes = params_buffer_bytes(hw_params);
 		return 0;
 	}
-	return snd_pcm_lib_malloc_pages(substream,
-					params_buffer_bytes(hw_params));
-}
-
-static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	if (fake_buffer)
-		return 0;
-	return snd_pcm_lib_free_pages(substream);
+	return 0;
 }
 
 static int dummy_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
-	struct dummy_model *model = dummy->model;
+	const struct dummy_model *model = dummy->model;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	const struct dummy_timer_ops *ops;
 	int err;
@@ -652,23 +644,19 @@
 	return virt_to_page(dummy_page[substream->stream]); /* the same page */
 }
 
-static struct snd_pcm_ops dummy_pcm_ops = {
+static const struct snd_pcm_ops dummy_pcm_ops = {
 	.open =		dummy_pcm_open,
 	.close =	dummy_pcm_close,
-	.ioctl =	snd_pcm_lib_ioctl,
 	.hw_params =	dummy_pcm_hw_params,
-	.hw_free =	dummy_pcm_hw_free,
 	.prepare =	dummy_pcm_prepare,
 	.trigger =	dummy_pcm_trigger,
 	.pointer =	dummy_pcm_pointer,
 };
 
-static struct snd_pcm_ops dummy_pcm_ops_no_buf = {
+static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {
 	.open =		dummy_pcm_open,
 	.close =	dummy_pcm_close,
-	.ioctl =	snd_pcm_lib_ioctl,
 	.hw_params =	dummy_pcm_hw_params,
-	.hw_free =	dummy_pcm_hw_free,
 	.prepare =	dummy_pcm_prepare,
 	.trigger =	dummy_pcm_trigger,
 	.pointer =	dummy_pcm_pointer,
@@ -682,7 +670,7 @@
 			      int substreams)
 {
 	struct snd_pcm *pcm;
-	struct snd_pcm_ops *ops;
+	const struct snd_pcm_ops *ops;
 	int err;
 
 	err = snd_pcm_new(dummy->card, "Dummy PCM", device,
@@ -700,9 +688,9 @@
 	pcm->info_flags = 0;
 	strcpy(pcm->name, "Dummy PCM");
 	if (!fake_buffer) {
-		snd_pcm_lib_preallocate_pages_for_all(pcm,
+		snd_pcm_set_managed_buffer_all(pcm,
 			SNDRV_DMA_TYPE_CONTINUOUS,
-			snd_dma_continuous_data(GFP_KERNEL),
+			NULL,
 			0, 64*1024);
 	}
 	return 0;
@@ -861,7 +849,7 @@
 	return changed;
 }
 
-static struct snd_kcontrol_new snd_dummy_controls[] = {
+static const struct snd_kcontrol_new snd_dummy_controls[] = {
 DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
 DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
 DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
@@ -913,10 +901,10 @@
 static void print_formats(struct snd_dummy *dummy,
 			  struct snd_info_buffer *buffer)
 {
-	int i;
+	snd_pcm_format_t i;
 
-	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
-		if (dummy->pcm_hw.formats & (1ULL << i))
+	pcm_for_each_format(i) {
+		if (dummy->pcm_hw.formats & pcm_format_to_bits(i))
 			snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
 	}
 }
@@ -924,7 +912,7 @@
 static void print_rates(struct snd_dummy *dummy,
 			struct snd_info_buffer *buffer)
 {
-	static int rates[] = {
+	static const int rates[] = {
 		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
 		64000, 88200, 96000, 176400, 192000,
 	};
@@ -956,7 +944,7 @@
 	.offset = offsetof(struct snd_pcm_hardware, item), \
 	.size = sizeof(dummy_pcm_hardware.item) }
 
-static struct dummy_hw_field fields[] = {
+static const struct dummy_hw_field fields[] = {
 	FIELD_ENTRY(formats, "%#llx"),
 	FIELD_ENTRY(rates, "%#x"),
 	FIELD_ENTRY(rate_min, "%d"),
@@ -1034,7 +1022,7 @@
 {
 	struct snd_card *card;
 	struct snd_dummy *dummy;
-	struct dummy_model *m = NULL, **mdl;
+	const struct dummy_model *m = NULL, **mdl;
 	int idx, err;
 	int dev = devptr->id;
 
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
deleted file mode 100644
index a3c1c06..0000000
--- a/sound/drivers/ml403-ac97cr.c
+++ /dev/null
@@ -1,1321 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * ALSA driver for Xilinx ML403 AC97 Controller Reference
- *   IP: opb_ac97_controller_ref_v1_00_a (EDK 8.1i)
- *   IP: opb_ac97_controller_ref_v1_00_a (EDK 9.1i)
- *
- *  Copyright (c) by 2007  Joachim Foerster <JOFT@gmx.de>
- */
-
-/* Some notes / status of this driver:
- *
- * - Don't wonder about some strange implementations of things - especially the
- * (heavy) shadowing of codec registers, with which I tried to reduce read
- * accesses to a minimum, because after a variable amount of accesses, the AC97
- * controller doesn't raise the register access finished bit anymore ...
- *
- * - Playback support seems to be pretty stable - no issues here.
- * - Capture support "works" now, too. Overruns don't happen any longer so often.
- *   But there might still be some ...
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/platform_device.h>
-
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-
-/* HZ */
-#include <linux/param.h>
-/* jiffies, time_*() */
-#include <linux/jiffies.h>
-/* schedule_timeout*() */
-#include <linux/sched.h>
-/* spin_lock*() */
-#include <linux/spinlock.h>
-/* struct mutex, mutex_init(), mutex_*lock() */
-#include <linux/mutex.h>
-
-/* snd_printk(), snd_printd() */
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/ac97_codec.h>
-
-#include "pcm-indirect2.h"
-
-
-#define SND_ML403_AC97CR_DRIVER "ml403-ac97cr"
-
-MODULE_AUTHOR("Joachim Foerster <JOFT@gmx.de>");
-MODULE_DESCRIPTION("Xilinx ML403 AC97 Controller Reference");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for ML403 AC97 Controller Reference.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable this ML403 AC97 Controller Reference.");
-
-/* Special feature options */
-/*#define CODEC_WRITE_CHECK_RAF*/ /* don't return after a write to a codec
-				   * register, while RAF bit is not set
-				   */
-/* Debug options for code which may be removed completely in a final version */
-#ifdef CONFIG_SND_DEBUG
-/*#define CODEC_STAT*/            /* turn on some minimal "statistics"
-				   * about codec register usage
-				   */
-#define SND_PCM_INDIRECT2_STAT    /* turn on some "statistics" about the
-				   * process of copying bytes from the
-				   * intermediate buffer to the hardware
-				   * fifo and the other way round
-				   */
-#endif
-
-/* Definition of a "level/facility dependent" printk(); may be removed
- * completely in a final version
- */
-#undef PDEBUG
-#ifdef CONFIG_SND_DEBUG
-/* "facilities" for PDEBUG */
-#define UNKNOWN       (1<<0)
-#define CODEC_SUCCESS (1<<1)
-#define CODEC_FAKE    (1<<2)
-#define INIT_INFO     (1<<3)
-#define INIT_FAILURE  (1<<4)
-#define WORK_INFO     (1<<5)
-#define WORK_FAILURE  (1<<6)
-
-#define PDEBUG_FACILITIES (UNKNOWN | INIT_FAILURE | WORK_FAILURE)
-
-#define PDEBUG(fac, fmt, args...) do { \
-		if (fac & PDEBUG_FACILITIES) \
-			snd_printd(KERN_DEBUG SND_ML403_AC97CR_DRIVER ": " \
-				   fmt, ##args); \
-	} while (0)
-#else
-#define PDEBUG(fac, fmt, args...) /* nothing */
-#endif
-
-
-
-/* Defines for "waits"/timeouts (portions of HZ=250 on arch/ppc by default) */
-#define CODEC_TIMEOUT_ON_INIT       5	/* timeout for checking for codec
-					 * readiness (after insmod)
-					 */
-#ifndef CODEC_WRITE_CHECK_RAF
-#define CODEC_WAIT_AFTER_WRITE    100	/* general, static wait after a write
-					 * access to a codec register, may be
-					 * 0 to completely remove wait
-					 */
-#else
-#define CODEC_TIMEOUT_AFTER_WRITE   5	/* timeout after a write access to a
-					 * codec register, if RAF bit is used
-					 */
-#endif
-#define CODEC_TIMEOUT_AFTER_READ    5	/* timeout after a read access to a
-					 * codec register (checking RAF bit)
-					 */
-
-/* Infrastructure for codec register shadowing */
-#define LM4550_REG_OK        (1<<0)   /* register exists */
-#define LM4550_REG_DONEREAD  (1<<1)   /* read register once, value should be
-				       * the same currently in the register
-				       */
-#define LM4550_REG_NOSAVE    (1<<2)   /* values written to this register will
-				       * not be saved in the register
-				       */
-#define LM4550_REG_NOSHADOW  (1<<3)   /* don't do register shadowing, use plain
-				       * hardware access
-				       */
-#define LM4550_REG_READONLY  (1<<4)   /* register is read only */
-#define LM4550_REG_FAKEPROBE (1<<5)   /* fake write _and_ read actions during
-				       * probe() correctly
-				       */
-#define LM4550_REG_FAKEREAD  (1<<6)   /* fake read access, always return
-				       * default value
-				       */
-#define LM4550_REG_ALLFAKE   (LM4550_REG_FAKEREAD | LM4550_REG_FAKEPROBE)
-
-struct lm4550_reg {
-	u16 value;
-	u16 flag;
-	u16 wmask;
-	u16 def;
-};
-
-struct lm4550_reg lm4550_regfile[64] = {
-	[AC97_RESET / 2]              = {.flag = LM4550_REG_OK \
-						| LM4550_REG_NOSAVE \
-						| LM4550_REG_FAKEREAD,
-					 .def = 0x0D50},
-	[AC97_MASTER / 2]             = {.flag = LM4550_REG_OK
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8000},
-	[AC97_HEADPHONE / 2]          = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8000},
-	[AC97_MASTER_MONO / 2]        = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x801F,
-					 .def = 0x8000},
-	[AC97_PC_BEEP / 2]            = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x801E,
-					 .def = 0x0},
-	[AC97_PHONE / 2]              = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x801F,
-					 .def = 0x8008},
-	[AC97_MIC / 2]                = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x805F,
-					 .def = 0x8008},
-	[AC97_LINE / 2]               = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8808},
-	[AC97_CD / 2]                 = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8808},
-	[AC97_VIDEO / 2]              = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8808},
-	[AC97_AUX / 2]                = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8808},
-	[AC97_PCM / 2]                = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x9F1F,
-					 .def = 0x8008},
-	[AC97_REC_SEL / 2]            = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x707,
-					 .def = 0x0},
-	[AC97_REC_GAIN / 2]           = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .wmask = 0x8F0F,
-					 .def = 0x8000},
-	[AC97_GENERAL_PURPOSE / 2]    = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .def = 0x0,
-					 .wmask = 0xA380},
-	[AC97_3D_CONTROL / 2]         = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEREAD \
-						| LM4550_REG_READONLY,
-					 .def = 0x0101},
-	[AC97_POWERDOWN / 2]          = {.flag = LM4550_REG_OK \
-						| LM4550_REG_NOSHADOW \
-						| LM4550_REG_NOSAVE,
-					 .wmask = 0xFF00},
-					/* may not write ones to
-					 * REF/ANL/DAC/ADC bits
-					 * FIXME: Is this ok?
-					 */
-	[AC97_EXTENDED_ID / 2]        = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEREAD \
-						| LM4550_REG_READONLY,
-					 .def = 0x0201}, /* primary codec */
-	[AC97_EXTENDED_STATUS / 2]    = {.flag = LM4550_REG_OK \
-						| LM4550_REG_NOSHADOW \
-						| LM4550_REG_NOSAVE,
-					 .wmask = 0x1},
-	[AC97_PCM_FRONT_DAC_RATE / 2] = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .def = 0xBB80,
-					 .wmask = 0xFFFF},
-	[AC97_PCM_LR_ADC_RATE / 2]    = {.flag = LM4550_REG_OK \
-						| LM4550_REG_FAKEPROBE,
-					 .def = 0xBB80,
-					 .wmask = 0xFFFF},
-	[AC97_VENDOR_ID1 / 2]         = {.flag = LM4550_REG_OK \
-						| LM4550_REG_READONLY \
-						| LM4550_REG_FAKEREAD,
-					 .def = 0x4E53},
-	[AC97_VENDOR_ID2 / 2]         = {.flag = LM4550_REG_OK \
-						| LM4550_REG_READONLY \
-						| LM4550_REG_FAKEREAD,
-					 .def = 0x4350}
-};
-
-#define LM4550_RF_OK(reg)    (lm4550_regfile[reg / 2].flag & LM4550_REG_OK)
-
-static void lm4550_regfile_init(void)
-{
-	int i;
-	for (i = 0; i < 64; i++)
-		if (lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE)
-			lm4550_regfile[i].value = lm4550_regfile[i].def;
-}
-
-static void lm4550_regfile_write_values_after_init(struct snd_ac97 *ac97)
-{
-	int i;
-	for (i = 0; i < 64; i++)
-		if ((lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) &&
-		    (lm4550_regfile[i].value != lm4550_regfile[i].def)) {
-			PDEBUG(CODEC_FAKE, "lm4550_regfile_write_values_after_"
-			       "init(): reg=0x%x value=0x%x / %d is different "
-			       "from def=0x%x / %d\n",
-			       i, lm4550_regfile[i].value,
-			       lm4550_regfile[i].value, lm4550_regfile[i].def,
-			       lm4550_regfile[i].def);
-			snd_ac97_write(ac97, i * 2, lm4550_regfile[i].value);
-			lm4550_regfile[i].flag |= LM4550_REG_DONEREAD;
-		}
-}
-
-
-/* direct registers */
-#define CR_REG(ml403_ac97cr, x) ((ml403_ac97cr)->port + CR_REG_##x)
-
-#define CR_REG_PLAYFIFO         0x00
-#define   CR_PLAYDATA(a)        ((a) & 0xFFFF)
-
-#define CR_REG_RECFIFO          0x04
-#define   CR_RECDATA(a)         ((a) & 0xFFFF)
-
-#define CR_REG_STATUS           0x08
-#define   CR_RECOVER            (1<<7)
-#define   CR_PLAYUNDER          (1<<6)
-#define   CR_CODECREADY         (1<<5)
-#define   CR_RAF                (1<<4)
-#define   CR_RECEMPTY           (1<<3)
-#define   CR_RECFULL            (1<<2)
-#define   CR_PLAYHALF           (1<<1)
-#define   CR_PLAYFULL           (1<<0)
-
-#define CR_REG_RESETFIFO        0x0C
-#define   CR_RECRESET           (1<<1)
-#define   CR_PLAYRESET          (1<<0)
-
-#define CR_REG_CODEC_ADDR       0x10
-/* UG082 says:
- * #define   CR_CODEC_ADDR(a)  ((a) << 1)
- * #define   CR_CODEC_READ     (1<<0)
- * #define   CR_CODEC_WRITE    (0<<0)
- */
-/* RefDesign example says: */
-#define   CR_CODEC_ADDR(a)      ((a) << 0)
-#define   CR_CODEC_READ         (1<<7)
-#define   CR_CODEC_WRITE        (0<<7)
-
-#define CR_REG_CODEC_DATAREAD   0x14
-#define   CR_CODEC_DATAREAD(v)  ((v) & 0xFFFF)
-
-#define CR_REG_CODEC_DATAWRITE  0x18
-#define   CR_CODEC_DATAWRITE(v) ((v) & 0xFFFF)
-
-#define CR_FIFO_SIZE            32
-
-struct snd_ml403_ac97cr {
-	/* lock for access to (controller) registers */
-	spinlock_t reg_lock;
-	/* mutex for the whole sequence of accesses to (controller) registers
-	 * which affect codec registers
-	 */
-	struct mutex cdc_mutex;
-
-	int irq; /* for playback */
-	int enable_irq;	/* for playback */
-
-	int capture_irq;
-	int enable_capture_irq;
-
-	struct resource *res_port;
-	void *port;
-
-	struct snd_ac97 *ac97;
-	int ac97_fake;
-#ifdef CODEC_STAT
-	int ac97_read;
-	int ac97_write;
-#endif
-
-	struct platform_device *pfdev;
-	struct snd_card *card;
-	struct snd_pcm *pcm;
-	struct snd_pcm_substream *playback_substream;
-	struct snd_pcm_substream *capture_substream;
-
-	struct snd_pcm_indirect2 ind_rec; /* for playback */
-	struct snd_pcm_indirect2 capture_ind2_rec;
-};
-
-static const struct snd_pcm_hardware snd_ml403_ac97cr_playback = {
-	.info =	            (SNDRV_PCM_INFO_MMAP |
-			     SNDRV_PCM_INFO_INTERLEAVED |
-			     SNDRV_PCM_INFO_MMAP_VALID),
-	.formats =          SNDRV_PCM_FMTBIT_S16_BE,
-	.rates =	    (SNDRV_PCM_RATE_CONTINUOUS |
-			     SNDRV_PCM_RATE_8000_48000),
-	.rate_min =	    4000,
-	.rate_max =	    48000,
-	.channels_min =     2,
-	.channels_max =     2,
-	.buffer_bytes_max = (128*1024),
-	.period_bytes_min = CR_FIFO_SIZE/2,
-	.period_bytes_max = (64*1024),
-	.periods_min =      2,
-	.periods_max =      (128*1024)/(CR_FIFO_SIZE/2),
-	.fifo_size =	    0,
-};
-
-static const struct snd_pcm_hardware snd_ml403_ac97cr_capture = {
-	.info =	            (SNDRV_PCM_INFO_MMAP |
-			     SNDRV_PCM_INFO_INTERLEAVED |
-			     SNDRV_PCM_INFO_MMAP_VALID),
-	.formats =          SNDRV_PCM_FMTBIT_S16_BE,
-	.rates =            (SNDRV_PCM_RATE_CONTINUOUS |
-			     SNDRV_PCM_RATE_8000_48000),
-	.rate_min =         4000,
-	.rate_max =         48000,
-	.channels_min =     2,
-	.channels_max =     2,
-	.buffer_bytes_max = (128*1024),
-	.period_bytes_min = CR_FIFO_SIZE/2,
-	.period_bytes_max = (64*1024),
-	.periods_min =      2,
-	.periods_max =      (128*1024)/(CR_FIFO_SIZE/2),
-	.fifo_size =	    0,
-};
-
-static size_t
-snd_ml403_ac97cr_playback_ind2_zero(struct snd_pcm_substream *substream,
-				    struct snd_pcm_indirect2 *rec)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	int copied_words = 0;
-	u32 full = 0;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	spin_lock(&ml403_ac97cr->reg_lock);
-	while ((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
-			CR_PLAYFULL)) != CR_PLAYFULL) {
-		out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 0);
-		copied_words++;
-	}
-	rec->hw_ready = 0;
-	spin_unlock(&ml403_ac97cr->reg_lock);
-
-	return (size_t) (copied_words * 2);
-}
-
-static size_t
-snd_ml403_ac97cr_playback_ind2_copy(struct snd_pcm_substream *substream,
-				    struct snd_pcm_indirect2 *rec,
-				    size_t bytes)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	u16 *src;
-	int copied_words = 0;
-	u32 full = 0;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-	src = (u16 *)(substream->runtime->dma_area + rec->sw_data);
-
-	spin_lock(&ml403_ac97cr->reg_lock);
-	while (((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
-			 CR_PLAYFULL)) != CR_PLAYFULL) && (bytes > 1)) {
-		out_be32(CR_REG(ml403_ac97cr, PLAYFIFO),
-			 CR_PLAYDATA(src[copied_words]));
-		copied_words++;
-		bytes = bytes - 2;
-	}
-	if (full != CR_PLAYFULL)
-		rec->hw_ready = 1;
-	else
-		rec->hw_ready = 0;
-	spin_unlock(&ml403_ac97cr->reg_lock);
-
-	return (size_t) (copied_words * 2);
-}
-
-static size_t
-snd_ml403_ac97cr_capture_ind2_null(struct snd_pcm_substream *substream,
-				   struct snd_pcm_indirect2 *rec)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	int copied_words = 0;
-	u32 empty = 0;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	spin_lock(&ml403_ac97cr->reg_lock);
-	while ((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
-			 CR_RECEMPTY)) != CR_RECEMPTY) {
-		volatile u32 trash;
-
-		trash = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, RECFIFO)));
-		/* Hmmmm, really necessary? Don't want call to in_be32()
-		 * to be optimised away!
-		 */
-		trash++;
-		copied_words++;
-	}
-	rec->hw_ready = 0;
-	spin_unlock(&ml403_ac97cr->reg_lock);
-
-	return (size_t) (copied_words * 2);
-}
-
-static size_t
-snd_ml403_ac97cr_capture_ind2_copy(struct snd_pcm_substream *substream,
-				   struct snd_pcm_indirect2 *rec, size_t bytes)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	u16 *dst;
-	int copied_words = 0;
-	u32 empty = 0;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-	dst = (u16 *)(substream->runtime->dma_area + rec->sw_data);
-
-	spin_lock(&ml403_ac97cr->reg_lock);
-	while (((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
-			  CR_RECEMPTY)) != CR_RECEMPTY) && (bytes > 1)) {
-		dst[copied_words] = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr,
-							      RECFIFO)));
-		copied_words++;
-		bytes = bytes - 2;
-	}
-	if (empty != CR_RECEMPTY)
-		rec->hw_ready = 1;
-	else
-		rec->hw_ready = 0;
-	spin_unlock(&ml403_ac97cr->reg_lock);
-
-	return (size_t) (copied_words * 2);
-}
-
-static snd_pcm_uframes_t
-snd_ml403_ac97cr_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	struct snd_pcm_indirect2 *ind2_rec = NULL;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	if (substream == ml403_ac97cr->playback_substream)
-		ind2_rec = &ml403_ac97cr->ind_rec;
-	if (substream == ml403_ac97cr->capture_substream)
-		ind2_rec = &ml403_ac97cr->capture_ind2_rec;
-
-	if (ind2_rec != NULL)
-		return snd_pcm_indirect2_pointer(substream, ind2_rec);
-	return (snd_pcm_uframes_t) 0;
-}
-
-static int
-snd_ml403_ac97cr_pcm_playback_trigger(struct snd_pcm_substream *substream,
-				      int cmd)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	int err = 0;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		PDEBUG(WORK_INFO, "trigger(playback): START\n");
-		ml403_ac97cr->ind_rec.hw_ready = 1;
-
-		/* clear play FIFO */
-		out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_PLAYRESET);
-
-		/* enable play irq */
-		ml403_ac97cr->enable_irq = 1;
-		enable_irq(ml403_ac97cr->irq);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		PDEBUG(WORK_INFO, "trigger(playback): STOP\n");
-		ml403_ac97cr->ind_rec.hw_ready = 0;
-#ifdef SND_PCM_INDIRECT2_STAT
-		snd_pcm_indirect2_stat(substream, &ml403_ac97cr->ind_rec);
-#endif
-		/* disable play irq */
-		disable_irq_nosync(ml403_ac97cr->irq);
-		ml403_ac97cr->enable_irq = 0;
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	PDEBUG(WORK_INFO, "trigger(playback): (done)\n");
-	return err;
-}
-
-static int
-snd_ml403_ac97cr_pcm_capture_trigger(struct snd_pcm_substream *substream,
-				      int cmd)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	int err = 0;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		PDEBUG(WORK_INFO, "trigger(capture): START\n");
-		ml403_ac97cr->capture_ind2_rec.hw_ready = 0;
-
-		/* clear record FIFO */
-		out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_RECRESET);
-
-		/* enable record irq */
-		ml403_ac97cr->enable_capture_irq = 1;
-		enable_irq(ml403_ac97cr->capture_irq);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		PDEBUG(WORK_INFO, "trigger(capture): STOP\n");
-		ml403_ac97cr->capture_ind2_rec.hw_ready = 0;
-#ifdef SND_PCM_INDIRECT2_STAT
-		snd_pcm_indirect2_stat(substream,
-				       &ml403_ac97cr->capture_ind2_rec);
-#endif
-		/* disable capture irq */
-		disable_irq_nosync(ml403_ac97cr->capture_irq);
-		ml403_ac97cr->enable_capture_irq = 0;
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	PDEBUG(WORK_INFO, "trigger(capture): (done)\n");
-	return err;
-}
-
-static int
-snd_ml403_ac97cr_pcm_playback_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	struct snd_pcm_runtime *runtime;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-	runtime = substream->runtime;
-
-	PDEBUG(WORK_INFO,
-	       "prepare(): period_bytes=%d, minperiod_bytes=%d\n",
-	       snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2);
-
-	/* set sampling rate */
-	snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_FRONT_DAC_RATE,
-			  runtime->rate);
-	PDEBUG(WORK_INFO, "prepare(): rate=%d\n", runtime->rate);
-
-	/* init struct for intermediate buffer */
-	memset(&ml403_ac97cr->ind_rec, 0,
-	       sizeof(struct snd_pcm_indirect2));
-	ml403_ac97cr->ind_rec.hw_buffer_size = CR_FIFO_SIZE;
-	ml403_ac97cr->ind_rec.sw_buffer_size =
-		snd_pcm_lib_buffer_bytes(substream);
-	ml403_ac97cr->ind_rec.min_periods = -1;
-	ml403_ac97cr->ind_rec.min_multiple =
-		snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2);
-	PDEBUG(WORK_INFO, "prepare(): hw_buffer_size=%d, "
-	       "sw_buffer_size=%d, min_multiple=%d\n",
-	       CR_FIFO_SIZE, ml403_ac97cr->ind_rec.sw_buffer_size,
-	       ml403_ac97cr->ind_rec.min_multiple);
-	return 0;
-}
-
-static int
-snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	struct snd_pcm_runtime *runtime;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-	runtime = substream->runtime;
-
-	PDEBUG(WORK_INFO,
-	       "prepare(capture): period_bytes=%d, minperiod_bytes=%d\n",
-	       snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2);
-
-	/* set sampling rate */
-	snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_LR_ADC_RATE,
-			  runtime->rate);
-	PDEBUG(WORK_INFO, "prepare(capture): rate=%d\n", runtime->rate);
-
-	/* init struct for intermediate buffer */
-	memset(&ml403_ac97cr->capture_ind2_rec, 0,
-	       sizeof(struct snd_pcm_indirect2));
-	ml403_ac97cr->capture_ind2_rec.hw_buffer_size = CR_FIFO_SIZE;
-	ml403_ac97cr->capture_ind2_rec.sw_buffer_size =
-		snd_pcm_lib_buffer_bytes(substream);
-	ml403_ac97cr->capture_ind2_rec.min_multiple =
-		snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2);
-	PDEBUG(WORK_INFO, "prepare(capture): hw_buffer_size=%d, "
-	       "sw_buffer_size=%d, min_multiple=%d\n", CR_FIFO_SIZE,
-	       ml403_ac97cr->capture_ind2_rec.sw_buffer_size,
-	       ml403_ac97cr->capture_ind2_rec.min_multiple);
-	return 0;
-}
-
-static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream)
-{
-	PDEBUG(WORK_INFO, "hw_free()\n");
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int
-snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream,
-			   struct snd_pcm_hw_params *hw_params)
-{
-	PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired "
-	       "period bytes=%d\n",
-	       params_buffer_bytes(hw_params), params_period_bytes(hw_params));
-	return snd_pcm_lib_malloc_pages(substream,
-					params_buffer_bytes(hw_params));
-}
-
-static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	struct snd_pcm_runtime *runtime;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-	runtime = substream->runtime;
-
-	PDEBUG(WORK_INFO, "open(playback)\n");
-	ml403_ac97cr->playback_substream = substream;
-	runtime->hw = snd_ml403_ac97cr_playback;
-
-	snd_pcm_hw_constraint_step(runtime, 0,
-				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-				   CR_FIFO_SIZE / 2);
-	return 0;
-}
-
-static int snd_ml403_ac97cr_capture_open(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	struct snd_pcm_runtime *runtime;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-	runtime = substream->runtime;
-
-	PDEBUG(WORK_INFO, "open(capture)\n");
-	ml403_ac97cr->capture_substream = substream;
-	runtime->hw = snd_ml403_ac97cr_capture;
-
-	snd_pcm_hw_constraint_step(runtime, 0,
-				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-				   CR_FIFO_SIZE / 2);
-	return 0;
-}
-
-static int snd_ml403_ac97cr_playback_close(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	PDEBUG(WORK_INFO, "close(playback)\n");
-	ml403_ac97cr->playback_substream = NULL;
-	return 0;
-}
-
-static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-
-	ml403_ac97cr = snd_pcm_substream_chip(substream);
-
-	PDEBUG(WORK_INFO, "close(capture)\n");
-	ml403_ac97cr->capture_substream = NULL;
-	return 0;
-}
-
-static const struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = {
-	.open = snd_ml403_ac97cr_playback_open,
-	.close = snd_ml403_ac97cr_playback_close,
-	.ioctl = snd_pcm_lib_ioctl,
-	.hw_params = snd_ml403_ac97cr_hw_params,
-	.hw_free = snd_ml403_ac97cr_hw_free,
-	.prepare = snd_ml403_ac97cr_pcm_playback_prepare,
-	.trigger = snd_ml403_ac97cr_pcm_playback_trigger,
-	.pointer = snd_ml403_ac97cr_pcm_pointer,
-};
-
-static const struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = {
-	.open = snd_ml403_ac97cr_capture_open,
-	.close = snd_ml403_ac97cr_capture_close,
-	.ioctl = snd_pcm_lib_ioctl,
-	.hw_params = snd_ml403_ac97cr_hw_params,
-	.hw_free = snd_ml403_ac97cr_hw_free,
-	.prepare = snd_ml403_ac97cr_pcm_capture_prepare,
-	.trigger = snd_ml403_ac97cr_pcm_capture_trigger,
-	.pointer = snd_ml403_ac97cr_pcm_pointer,
-};
-
-static irqreturn_t snd_ml403_ac97cr_irq(int irq, void *dev_id)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	struct platform_device *pfdev;
-	int cmp_irq;
-
-	ml403_ac97cr = (struct snd_ml403_ac97cr *)dev_id;
-	if (ml403_ac97cr == NULL)
-		return IRQ_NONE;
-
-	pfdev = ml403_ac97cr->pfdev;
-
-	/* playback interrupt */
-	cmp_irq = platform_get_irq(pfdev, 0);
-	if (irq == cmp_irq) {
-		if (ml403_ac97cr->enable_irq)
-			snd_pcm_indirect2_playback_interrupt(
-				ml403_ac97cr->playback_substream,
-				&ml403_ac97cr->ind_rec,
-				snd_ml403_ac97cr_playback_ind2_copy,
-				snd_ml403_ac97cr_playback_ind2_zero);
-		else
-			goto __disable_irq;
-	} else {
-		/* record interrupt */
-		cmp_irq = platform_get_irq(pfdev, 1);
-		if (irq == cmp_irq) {
-			if (ml403_ac97cr->enable_capture_irq)
-				snd_pcm_indirect2_capture_interrupt(
-					ml403_ac97cr->capture_substream,
-					&ml403_ac97cr->capture_ind2_rec,
-					snd_ml403_ac97cr_capture_ind2_copy,
-					snd_ml403_ac97cr_capture_ind2_null);
-			else
-				goto __disable_irq;
-		} else
-			return IRQ_NONE;
-	}
-	return IRQ_HANDLED;
-
-__disable_irq:
-	PDEBUG(INIT_INFO, "irq(): irq %d is meant to be disabled! So, now try "
-	       "to disable it _really_!\n", irq);
-	disable_irq_nosync(irq);
-	return IRQ_HANDLED;
-}
-
-static unsigned short
-snd_ml403_ac97cr_codec_read(struct snd_ac97 *ac97, unsigned short reg)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data;
-#ifdef CODEC_STAT
-	u32 stat;
-	u32 rafaccess = 0;
-#endif
-	unsigned long end_time;
-	u16 value = 0;
-
-	if (!LM4550_RF_OK(reg)) {
-		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-			   "access to unknown/unused codec register 0x%x "
-			   "ignored!\n", reg);
-		return 0;
-	}
-	/* check if we can fake/answer this access from our shadow register */
-	if ((lm4550_regfile[reg / 2].flag &
-	     (LM4550_REG_DONEREAD | LM4550_REG_ALLFAKE)) &&
-	    !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) {
-		if (lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEREAD) {
-			PDEBUG(CODEC_FAKE, "codec_read(): faking read from "
-			       "reg=0x%x, val=0x%x / %d\n",
-			       reg, lm4550_regfile[reg / 2].def,
-			       lm4550_regfile[reg / 2].def);
-			return lm4550_regfile[reg / 2].def;
-		} else if ((lm4550_regfile[reg / 2].flag &
-			    LM4550_REG_FAKEPROBE) &&
-			   ml403_ac97cr->ac97_fake) {
-			PDEBUG(CODEC_FAKE, "codec_read(): faking read from "
-			       "reg=0x%x, val=0x%x / %d (probe)\n",
-			       reg, lm4550_regfile[reg / 2].value,
-			       lm4550_regfile[reg / 2].value);
-			return lm4550_regfile[reg / 2].value;
-		} else {
-#ifdef CODEC_STAT
-			PDEBUG(CODEC_FAKE, "codec_read(): read access "
-			       "answered by shadow register 0x%x (value=0x%x "
-			       "/ %d) (cw=%d cr=%d)\n",
-			       reg, lm4550_regfile[reg / 2].value,
-			       lm4550_regfile[reg / 2].value,
-			       ml403_ac97cr->ac97_write,
-			       ml403_ac97cr->ac97_read);
-#else
-			PDEBUG(CODEC_FAKE, "codec_read(): read access "
-			       "answered by shadow register 0x%x (value=0x%x "
-			       "/ %d)\n",
-			       reg, lm4550_regfile[reg / 2].value,
-			       lm4550_regfile[reg / 2].value);
-#endif
-			return lm4550_regfile[reg / 2].value;
-		}
-	}
-	/* if we are here, we _have_ to access the codec really, no faking */
-	if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0)
-		return 0;
-#ifdef CODEC_STAT
-	ml403_ac97cr->ac97_read++;
-#endif
-	spin_lock(&ml403_ac97cr->reg_lock);
-	out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR),
-		 CR_CODEC_ADDR(reg) | CR_CODEC_READ);
-	spin_unlock(&ml403_ac97cr->reg_lock);
-	end_time = jiffies + (HZ / CODEC_TIMEOUT_AFTER_READ);
-	do {
-		spin_lock(&ml403_ac97cr->reg_lock);
-#ifdef CODEC_STAT
-		rafaccess++;
-		stat = in_be32(CR_REG(ml403_ac97cr, STATUS));
-		if ((stat & CR_RAF) == CR_RAF) {
-			value = CR_CODEC_DATAREAD(
-				in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD)));
-			PDEBUG(CODEC_SUCCESS, "codec_read(): (done) reg=0x%x, "
-			       "value=0x%x / %d (STATUS=0x%x)\n",
-			       reg, value, value, stat);
-#else
-		if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) &
-		     CR_RAF) == CR_RAF) {
-			value = CR_CODEC_DATAREAD(
-				in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD)));
-			PDEBUG(CODEC_SUCCESS, "codec_read(): (done) "
-			       "reg=0x%x, value=0x%x / %d\n",
-			       reg, value, value);
-#endif
-			lm4550_regfile[reg / 2].value = value;
-			lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD;
-			spin_unlock(&ml403_ac97cr->reg_lock);
-			mutex_unlock(&ml403_ac97cr->cdc_mutex);
-			return value;
-		}
-		spin_unlock(&ml403_ac97cr->reg_lock);
-		schedule_timeout_uninterruptible(1);
-	} while (time_after(end_time, jiffies));
-	/* read the DATAREAD register anyway, see comment below */
-	spin_lock(&ml403_ac97cr->reg_lock);
-	value =
-	    CR_CODEC_DATAREAD(in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD)));
-	spin_unlock(&ml403_ac97cr->reg_lock);
-#ifdef CODEC_STAT
-	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-		   "timeout while codec read! "
-		   "(reg=0x%x, last STATUS=0x%x, DATAREAD=0x%x / %d, %d) "
-		   "(cw=%d, cr=%d)\n",
-		   reg, stat, value, value, rafaccess,
-		   ml403_ac97cr->ac97_write, ml403_ac97cr->ac97_read);
-#else
-	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-		   "timeout while codec read! "
-		   "(reg=0x%x, DATAREAD=0x%x / %d)\n",
-		   reg, value, value);
-#endif
-	/* BUG: This is PURE speculation! But after _most_ read timeouts the
-	 * value in the register is ok!
-	 */
-	lm4550_regfile[reg / 2].value = value;
-	lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD;
-	mutex_unlock(&ml403_ac97cr->cdc_mutex);
-	return value;
-}
-
-static void
-snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg,
-			     unsigned short val)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data;
-
-#ifdef CODEC_STAT
-	u32 stat;
-	u32 rafaccess = 0;
-#endif
-#ifdef CODEC_WRITE_CHECK_RAF
-	unsigned long end_time;
-#endif
-
-	if (!LM4550_RF_OK(reg)) {
-		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-			   "access to unknown/unused codec register 0x%x "
-			   "ignored!\n", reg);
-		return;
-	}
-	if (lm4550_regfile[reg / 2].flag & LM4550_REG_READONLY) {
-		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-			   "write access to read only codec register 0x%x "
-			   "ignored!\n", reg);
-		return;
-	}
-	if ((val & lm4550_regfile[reg / 2].wmask) != val) {
-		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-			   "write access to codec register 0x%x "
-			   "with bad value 0x%x / %d!\n",
-			   reg, val, val);
-		val = val & lm4550_regfile[reg / 2].wmask;
-	}
-	if (((lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEPROBE) &&
-	     ml403_ac97cr->ac97_fake) &&
-	    !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) {
-		PDEBUG(CODEC_FAKE, "codec_write(): faking write to reg=0x%x, "
-		       "val=0x%x / %d\n", reg, val, val);
-		lm4550_regfile[reg / 2].value = (val &
-						lm4550_regfile[reg / 2].wmask);
-		return;
-	}
-	if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0)
-		return;
-#ifdef CODEC_STAT
-	ml403_ac97cr->ac97_write++;
-#endif
-	spin_lock(&ml403_ac97cr->reg_lock);
-	out_be32(CR_REG(ml403_ac97cr, CODEC_DATAWRITE),
-		 CR_CODEC_DATAWRITE(val));
-	out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR),
-		 CR_CODEC_ADDR(reg) | CR_CODEC_WRITE);
-	spin_unlock(&ml403_ac97cr->reg_lock);
-#ifdef CODEC_WRITE_CHECK_RAF
-	/* check CR_CODEC_RAF bit to see if write access to register is done;
-	 * loop until bit is set or timeout happens
-	 */
-	end_time = jiffies + HZ / CODEC_TIMEOUT_AFTER_WRITE;
-	do {
-		spin_lock(&ml403_ac97cr->reg_lock);
-#ifdef CODEC_STAT
-		rafaccess++;
-		stat = in_be32(CR_REG(ml403_ac97cr, STATUS))
-		if ((stat & CR_RAF) == CR_RAF) {
-#else
-		if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) &
-		     CR_RAF) == CR_RAF) {
-#endif
-			PDEBUG(CODEC_SUCCESS, "codec_write(): (done) "
-			       "reg=0x%x, value=%d / 0x%x\n",
-			       reg, val, val);
-			if (!(lm4550_regfile[reg / 2].flag &
-			      LM4550_REG_NOSHADOW) &&
-			    !(lm4550_regfile[reg / 2].flag &
-			      LM4550_REG_NOSAVE))
-				lm4550_regfile[reg / 2].value = val;
-			lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD;
-			spin_unlock(&ml403_ac97cr->reg_lock);
-			mutex_unlock(&ml403_ac97cr->cdc_mutex);
-			return;
-		}
-		spin_unlock(&ml403_ac97cr->reg_lock);
-		schedule_timeout_uninterruptible(1);
-	} while (time_after(end_time, jiffies));
-#ifdef CODEC_STAT
-	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-		   "timeout while codec write "
-		   "(reg=0x%x, val=0x%x / %d, last STATUS=0x%x, %d) "
-		   "(cw=%d, cr=%d)\n",
-		   reg, val, val, stat, rafaccess, ml403_ac97cr->ac97_write,
-		   ml403_ac97cr->ac97_read);
-#else
-	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
-		   "timeout while codec write (reg=0x%x, val=0x%x / %d)\n",
-		   reg, val, val);
-#endif
-#else /* CODEC_WRITE_CHECK_RAF */
-#if CODEC_WAIT_AFTER_WRITE > 0
-	/* officially, in AC97 spec there is no possibility for a AC97
-	 * controller to determine, if write access is done or not - so: How
-	 * is Xilinx able to provide a RAF bit for write access?
-	 * => very strange, thus just don't check RAF bit (compare with
-	 * Xilinx's example app in EDK 8.1i) and wait
-	 */
-	schedule_timeout_uninterruptible(HZ / CODEC_WAIT_AFTER_WRITE);
-#endif
-	PDEBUG(CODEC_SUCCESS, "codec_write(): (done) "
-	       "reg=0x%x, value=%d / 0x%x (no RAF check)\n",
-	       reg, val, val);
-#endif
-	mutex_unlock(&ml403_ac97cr->cdc_mutex);
-	return;
-}
-
-static int
-snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr)
-{
-	unsigned long end_time;
-	PDEBUG(INIT_INFO, "chip_init():\n");
-	end_time = jiffies + HZ / CODEC_TIMEOUT_ON_INIT;
-	do {
-		if (in_be32(CR_REG(ml403_ac97cr, STATUS)) & CR_CODECREADY) {
-			/* clear both hardware FIFOs */
-			out_be32(CR_REG(ml403_ac97cr, RESETFIFO),
-				 CR_RECRESET | CR_PLAYRESET);
-			PDEBUG(INIT_INFO, "chip_init(): (done)\n");
-			return 0;
-		}
-		schedule_timeout_uninterruptible(1);
-	} while (time_after(end_time, jiffies));
-	snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
-		   "timeout while waiting for codec, "
-		   "not ready!\n");
-	return -EBUSY;
-}
-
-static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr)
-{
-	PDEBUG(INIT_INFO, "free():\n");
-	/* irq release */
-	if (ml403_ac97cr->irq >= 0)
-		free_irq(ml403_ac97cr->irq, ml403_ac97cr);
-	if (ml403_ac97cr->capture_irq >= 0)
-		free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr);
-	/* give back "port" */
-	iounmap(ml403_ac97cr->port);
-	kfree(ml403_ac97cr);
-	PDEBUG(INIT_INFO, "free(): (done)\n");
-	return 0;
-}
-
-static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr = snddev->device_data;
-	PDEBUG(INIT_INFO, "dev_free():\n");
-	return snd_ml403_ac97cr_free(ml403_ac97cr);
-}
-
-static int
-snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
-			struct snd_ml403_ac97cr **rml403_ac97cr)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr;
-	int err;
-	static struct snd_device_ops ops = {
-		.dev_free = snd_ml403_ac97cr_dev_free,
-	};
-	struct resource *resource;
-	int irq;
-
-	*rml403_ac97cr = NULL;
-	ml403_ac97cr = kzalloc(sizeof(*ml403_ac97cr), GFP_KERNEL);
-	if (ml403_ac97cr == NULL)
-		return -ENOMEM;
-	spin_lock_init(&ml403_ac97cr->reg_lock);
-	mutex_init(&ml403_ac97cr->cdc_mutex);
-	ml403_ac97cr->card = card;
-	ml403_ac97cr->pfdev = pfdev;
-	ml403_ac97cr->irq = -1;
-	ml403_ac97cr->enable_irq = 0;
-	ml403_ac97cr->capture_irq = -1;
-	ml403_ac97cr->enable_capture_irq = 0;
-	ml403_ac97cr->port = NULL;
-	ml403_ac97cr->res_port = NULL;
-
-	PDEBUG(INIT_INFO, "Trying to reserve resources now ...\n");
-	resource = platform_get_resource(pfdev, IORESOURCE_MEM, 0);
-	/* get "port" */
-	ml403_ac97cr->port = ioremap_nocache(resource->start,
-					     (resource->end) -
-					     (resource->start) + 1);
-	if (ml403_ac97cr->port == NULL) {
-		snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
-			   "unable to remap memory region (%pR)\n",
-			   resource);
-		snd_ml403_ac97cr_free(ml403_ac97cr);
-		return -EBUSY;
-	}
-	snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": "
-		   "remap controller memory region to "
-		   "0x%x done\n", (unsigned int)ml403_ac97cr->port);
-	/* get irq */
-	irq = platform_get_irq(pfdev, 0);
-	if (request_irq(irq, snd_ml403_ac97cr_irq, 0,
-			dev_name(&pfdev->dev), (void *)ml403_ac97cr)) {
-		snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
-			   "unable to grab IRQ %d\n",
-			   irq);
-		snd_ml403_ac97cr_free(ml403_ac97cr);
-		return -EBUSY;
-	}
-	ml403_ac97cr->irq = irq;
-	snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": "
-		   "request (playback) irq %d done\n",
-		   ml403_ac97cr->irq);
-	irq = platform_get_irq(pfdev, 1);
-	if (request_irq(irq, snd_ml403_ac97cr_irq, 0,
-			dev_name(&pfdev->dev), (void *)ml403_ac97cr)) {
-		snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
-			   "unable to grab IRQ %d\n",
-			   irq);
-		snd_ml403_ac97cr_free(ml403_ac97cr);
-		return -EBUSY;
-	}
-	ml403_ac97cr->capture_irq = irq;
-	snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": "
-		   "request (capture) irq %d done\n",
-		   ml403_ac97cr->capture_irq);
-
-	err = snd_ml403_ac97cr_chip_init(ml403_ac97cr);
-	if (err < 0) {
-		snd_ml403_ac97cr_free(ml403_ac97cr);
-		return err;
-	}
-
-	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ml403_ac97cr, &ops);
-	if (err < 0) {
-		PDEBUG(INIT_FAILURE, "probe(): snd_device_new() failed!\n");
-		snd_ml403_ac97cr_free(ml403_ac97cr);
-		return err;
-	}
-
-	*rml403_ac97cr = ml403_ac97cr;
-	return 0;
-}
-
-static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97)
-{
-	struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data;
-	PDEBUG(INIT_INFO, "mixer_free():\n");
-	ml403_ac97cr->ac97 = NULL;
-	PDEBUG(INIT_INFO, "mixer_free(): (done)\n");
-}
-
-static int
-snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr)
-{
-	struct snd_ac97_bus *bus;
-	struct snd_ac97_template ac97;
-	int err;
-	static struct snd_ac97_bus_ops ops = {
-		.write = snd_ml403_ac97cr_codec_write,
-		.read = snd_ml403_ac97cr_codec_read,
-	};
-	PDEBUG(INIT_INFO, "mixer():\n");
-	err = snd_ac97_bus(ml403_ac97cr->card, 0, &ops, NULL, &bus);
-	if (err < 0)
-		return err;
-
-	memset(&ac97, 0, sizeof(ac97));
-	ml403_ac97cr->ac97_fake = 1;
-	lm4550_regfile_init();
-#ifdef CODEC_STAT
-	ml403_ac97cr->ac97_read = 0;
-	ml403_ac97cr->ac97_write = 0;
-#endif
-	ac97.private_data = ml403_ac97cr;
-	ac97.private_free = snd_ml403_ac97cr_mixer_free;
-	ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM |
-	    AC97_SCAP_NO_SPDIF;
-	err = snd_ac97_mixer(bus, &ac97, &ml403_ac97cr->ac97);
-	ml403_ac97cr->ac97_fake = 0;
-	lm4550_regfile_write_values_after_init(ml403_ac97cr->ac97);
-	PDEBUG(INIT_INFO, "mixer(): (done) snd_ac97_mixer()=%d\n", err);
-	return err;
-}
-
-static int
-snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
-{
-	struct snd_pcm *pcm;
-	int err;
-
-	err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1,
-			  &pcm);
-	if (err < 0)
-		return err;
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-			&snd_ml403_ac97cr_playback_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-			&snd_ml403_ac97cr_capture_ops);
-	pcm->private_data = ml403_ac97cr;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, "ML403AC97CR DAC/ADC");
-	ml403_ac97cr->pcm = pcm;
-
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-					  snd_dma_continuous_data(GFP_KERNEL),
-					  64 * 1024,
-					  128 * 1024);
-	return 0;
-}
-
-static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
-{
-	struct snd_card *card;
-	struct snd_ml403_ac97cr *ml403_ac97cr = NULL;
-	int err;
-	int dev = pfdev->id;
-
-	if (dev >= SNDRV_CARDS)
-		return -ENODEV;
-	if (!enable[dev])
-		return -ENOENT;
-
-	err = snd_card_new(&pfdev->dev, index[dev], id[dev], THIS_MODULE,
-			   0, &card);
-	if (err < 0)
-		return err;
-	err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
-	if (err < 0) {
-		PDEBUG(INIT_FAILURE, "probe(): create failed!\n");
-		snd_card_free(card);
-		return err;
-	}
-	PDEBUG(INIT_INFO, "probe(): create done\n");
-	card->private_data = ml403_ac97cr;
-	err = snd_ml403_ac97cr_mixer(ml403_ac97cr);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	PDEBUG(INIT_INFO, "probe(): mixer done\n");
-	err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	PDEBUG(INIT_INFO, "probe(): PCM done\n");
-	strcpy(card->driver, SND_ML403_AC97CR_DRIVER);
-	strcpy(card->shortname, "ML403 AC97 Controller Reference");
-	sprintf(card->longname, "%s %s at 0x%lx, irq %i & %i, device %i",
-		card->shortname, card->driver,
-		(unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq,
-		ml403_ac97cr->capture_irq, dev + 1);
-
-	err = snd_card_register(card);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	platform_set_drvdata(pfdev, card);
-	PDEBUG(INIT_INFO, "probe(): (done)\n");
-	return 0;
-}
-
-static int snd_ml403_ac97cr_remove(struct platform_device *pfdev)
-{
-	snd_card_free(platform_get_drvdata(pfdev));
-	return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" SND_ML403_AC97CR_DRIVER);
-
-static struct platform_driver snd_ml403_ac97cr_driver = {
-	.probe = snd_ml403_ac97cr_probe,
-	.remove = snd_ml403_ac97cr_remove,
-	.driver = {
-		.name = SND_ML403_AC97CR_DRIVER,
-	},
-};
-
-module_platform_driver(snd_ml403_ac97cr_driver);
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index 44776e1..9c708b6 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -261,7 +261,7 @@
  */
 static u8 mts64_map_midi_input(u8 c)
 {
-	static u8 map[] = { 0, 1, 4, 2, 3 };
+	static const u8 map[] = { 0, 1, 4, 2, 3 };
 
 	return map[c];
 }
@@ -353,7 +353,7 @@
 			      u8 seconds, u8 frames,
 			      u8 idx)
 {
-	static u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24, 
+	static const u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24,
 			     MTS64_CMD_SMPTE_FPS_25,
 			     MTS64_CMD_SMPTE_FPS_2997, 
 			     MTS64_CMD_SMPTE_FPS_30D,
@@ -467,7 +467,7 @@
 	return changed;
 }
 
-static struct snd_kcontrol_new mts64_ctl_smpte_switch = {
+static const struct snd_kcontrol_new mts64_ctl_smpte_switch = {
 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
 	.name  = "SMPTE Playback Switch",
 	.index = 0,
@@ -540,7 +540,7 @@
 	return changed;
 }
 
-static struct snd_kcontrol_new mts64_ctl_smpte_time_hours = {
+static const struct snd_kcontrol_new mts64_ctl_smpte_time_hours = {
 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
 	.name  = "SMPTE Time Hours",
 	.index = 0,
@@ -551,7 +551,7 @@
 	.put  = snd_mts64_ctl_smpte_time_put
 };
 
-static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = {
+static const struct snd_kcontrol_new mts64_ctl_smpte_time_minutes = {
 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
 	.name  = "SMPTE Time Minutes",
 	.index = 0,
@@ -562,7 +562,7 @@
 	.put  = snd_mts64_ctl_smpte_time_put
 };
 
-static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = {
+static const struct snd_kcontrol_new mts64_ctl_smpte_time_seconds = {
 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
 	.name  = "SMPTE Time Seconds",
 	.index = 0,
@@ -573,7 +573,7 @@
 	.put  = snd_mts64_ctl_smpte_time_put
 };
 
-static struct snd_kcontrol_new mts64_ctl_smpte_time_frames = {
+static const struct snd_kcontrol_new mts64_ctl_smpte_time_frames = {
 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
 	.name  = "SMPTE Time Frames",
 	.index = 0,
@@ -625,7 +625,7 @@
 	return changed;
 }
 
-static struct snd_kcontrol_new mts64_ctl_smpte_fps = {
+static const struct snd_kcontrol_new mts64_ctl_smpte_fps = {
 	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,
 	.name  = "SMPTE Fps",
 	.index = 0,
@@ -641,7 +641,7 @@
 				struct mts64 *mts)
 {
 	int err, i;
-	static struct snd_kcontrol_new *control[] = {
+	static const struct snd_kcontrol_new *control[] = {
 		&mts64_ctl_smpte_switch,
 		&mts64_ctl_smpte_time_hours,
 		&mts64_ctl_smpte_time_minutes,
diff --git a/sound/drivers/opl3/opl3_drums.c b/sound/drivers/opl3/opl3_drums.c
index cc7fb35..ccc49f3 100644
--- a/sound/drivers/opl3/opl3_drums.c
+++ b/sound/drivers/opl3/opl3_drums.c
@@ -7,7 +7,7 @@
 
 #include "opl3_voice.h"
 
-static char snd_opl3_drum_table[47] =
+static const char snd_opl3_drum_table[47] =
 {
 	OPL3_BASSDRUM_ON,  OPL3_BASSDRUM_ON,  OPL3_HIHAT_ON,	/* 35 - 37 */
 	OPL3_SNAREDRUM_ON, OPL3_HIHAT_ON,     OPL3_SNAREDRUM_ON, /* 38 - 40 */
@@ -47,25 +47,25 @@
 	unsigned char feedback_connection;
 };
 
-static struct snd_opl3_drum_voice bass_op0 = {6, 0, 0x00, 0x32, 0xf8, 0x66, 0x30, 0x00};
-static struct snd_opl3_drum_voice bass_op1 = {6, 1, 0x00, 0x03, 0xf6, 0x57, 0x30, 0x00};
-static struct snd_opl3_drum_note bass_note = {6, 0x90, 0x09};
+static const struct snd_opl3_drum_voice bass_op0 = {6, 0, 0x00, 0x32, 0xf8, 0x66, 0x30, 0x00};
+static const struct snd_opl3_drum_voice bass_op1 = {6, 1, 0x00, 0x03, 0xf6, 0x57, 0x30, 0x00};
+static const struct snd_opl3_drum_note bass_note = {6, 0x90, 0x09};
 
-static struct snd_opl3_drum_voice hihat = {7, 0, 0x00, 0x03, 0xf0, 0x06, 0x20, 0x00};
+static const struct snd_opl3_drum_voice hihat = {7, 0, 0x00, 0x03, 0xf0, 0x06, 0x20, 0x00};
 
-static struct snd_opl3_drum_voice snare = {7, 1, 0x00, 0x03, 0xf0, 0x07, 0x20, 0x02};
-static struct snd_opl3_drum_note snare_note = {7, 0xf4, 0x0d};
+static const struct snd_opl3_drum_voice snare = {7, 1, 0x00, 0x03, 0xf0, 0x07, 0x20, 0x02};
+static const struct snd_opl3_drum_note snare_note = {7, 0xf4, 0x0d};
 
-static struct snd_opl3_drum_voice tomtom = {8, 0, 0x02, 0x03, 0xf0, 0x06, 0x10, 0x00};
-static struct snd_opl3_drum_note tomtom_note = {8, 0xf4, 0x09};
+static const struct snd_opl3_drum_voice tomtom = {8, 0, 0x02, 0x03, 0xf0, 0x06, 0x10, 0x00};
+static const struct snd_opl3_drum_note tomtom_note = {8, 0xf4, 0x09};
 
-static struct snd_opl3_drum_voice cymbal = {8, 1, 0x04, 0x03, 0xf0, 0x06, 0x10, 0x00};
+static const struct snd_opl3_drum_voice cymbal = {8, 1, 0x04, 0x03, 0xf0, 0x06, 0x10, 0x00};
 
 /*
  * set drum voice characteristics
  */
 static void snd_opl3_drum_voice_set(struct snd_opl3 *opl3,
-				    struct snd_opl3_drum_voice *data)
+				    const struct snd_opl3_drum_voice *data)
 {
 	unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
 	unsigned char voice_offset = data->voice;
@@ -100,7 +100,7 @@
  * Set drum voice pitch
  */
 static void snd_opl3_drum_note_set(struct snd_opl3 *opl3,
-				   struct snd_opl3_drum_note *data)
+				   const struct snd_opl3_drum_note *data)
 {
 	unsigned char voice_offset = data->voice;
 	unsigned short opl3_reg;
@@ -118,7 +118,7 @@
  * Set drum voice volume and position
  */
 static void snd_opl3_drum_vol_set(struct snd_opl3 *opl3,
-				  struct snd_opl3_drum_voice *data,
+				  const struct snd_opl3_drum_voice *data,
 				  int vel, struct snd_midi_channel *chan)
 {
 	unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
@@ -170,7 +170,7 @@
 			  struct snd_midi_channel *chan)
 {
 	unsigned char drum_mask;
-	struct snd_opl3_drum_voice *drum_voice;
+	const struct snd_opl3_drum_voice *drum_voice;
 
 	if (!(opl3->drum_reg & OPL3_PERCUSSION_ENABLE))
 		return;
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index cbdec28..9259522 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -214,7 +214,7 @@
 
  */
 
-static struct snd_timer_hardware snd_opl3_timer1 =
+static const struct snd_timer_hardware snd_opl3_timer1 =
 {
 	.flags =	SNDRV_TIMER_HW_STOP,
 	.resolution =	80000,
@@ -223,7 +223,7 @@
 	.stop =		snd_opl3_timer1_stop,
 };
 
-static struct snd_timer_hardware snd_opl3_timer2 =
+static const struct snd_timer_hardware snd_opl3_timer2 =
 {
 	.flags =	SNDRV_TIMER_HW_STOP,
 	.resolution =	320000,
@@ -332,7 +332,7 @@
 		 unsigned short hardware,
 		 struct snd_opl3 **ropl3)
 {
-	static struct snd_device_ops ops = {
+	static const struct snd_device_ops ops = {
 		.dev_free = snd_opl3_dev_free,
 	};
 	struct snd_opl3 *opl3;
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 280cc79..a2583a3 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -23,7 +23,7 @@
  * it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>)
  */
 
-static char opl3_volume_table[128] =
+static const char opl3_volume_table[128] =
 {
 	-63, -48, -40, -35, -32, -29, -27, -26,
 	-24, -23, -21, -20, -19, -18, -18, -17,
@@ -69,7 +69,7 @@
 /*
  * Converts the note frequency to block and fnum values for the FM chip
  */
-static short opl3_note_table[16] =
+static const short opl3_note_table[16] =
 {
 	305, 323,	/* for pitch bending, -2 semitones */
 	343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647,
@@ -266,7 +266,7 @@
 /* ------------------------------ */
 
 
-static int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
+static const int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
 	0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14
 };
 
@@ -354,7 +354,7 @@
 			instr_4op = 1;
 			break;
 		}
-		/* fall through */
+		fallthrough;
 	default:
 		spin_unlock_irqrestore(&opl3->voice_lock, flags);
 		return;
@@ -398,7 +398,7 @@
 	}
 	if (instr_4op) {
 		vp2 = &opl3->voices[voice + 3];
-		if (vp->state > 0) {
+		if (vp2->state > 0) {
 			opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK +
 					       voice_offset + 3);
 			reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
@@ -443,7 +443,7 @@
 		switch (connection) {
 		case 0x03:
 			snd_opl3_calc_volume(&vol_op[2], vel, chan);
-			/* fallthru */
+			fallthrough;
 		case 0x02:
 			snd_opl3_calc_volume(&vol_op[0], vel, chan);
 			break;
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index d0cf2fb..7bf0d5f 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -16,7 +16,7 @@
 
 /* operators */
 
-static struct snd_seq_oss_callback oss_callback = {
+static const struct snd_seq_oss_callback oss_callback = {
 	.owner = 	THIS_MODULE,
 	.open =		snd_opl3_open_seq_oss,
 	.close =	snd_opl3_close_seq_oss,
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index 20f2f51..cd2a01b 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -128,7 +128,7 @@
 /*
  * MIDI emulation operators
  */
-struct snd_midi_op opl3_ops = {
+const struct snd_midi_op opl3_ops = {
 	.note_on =		snd_opl3_note_on,
 	.note_off =		snd_opl3_note_off,
 	.key_press =		snd_opl3_key_press,
diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h
index dc0626a..be9ccca 100644
--- a/sound/drivers/opl3/opl3_voice.h
+++ b/sound/drivers/opl3/opl3_voice.h
@@ -41,6 +41,6 @@
 
 extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
 extern bool use_internal_drums;
-extern struct snd_midi_op opl3_ops;
+extern const struct snd_midi_op opl3_ops;
 
 #endif
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c
index 901d339..035645e 100644
--- a/sound/drivers/opl4/opl4_lib.c
+++ b/sound/drivers/opl4/opl4_lib.c
@@ -184,7 +184,7 @@
 	struct snd_opl4 *opl4;
 	struct snd_opl3 *opl3;
 	int err;
-	static struct snd_device_ops ops = {
+	static const struct snd_device_ops ops = {
 		.dev_free = snd_opl4_dev_free
 	};
 
diff --git a/sound/drivers/opl4/opl4_mixer.c b/sound/drivers/opl4/opl4_mixer.c
index 7d4b3cc..fa1e6ef 100644
--- a/sound/drivers/opl4/opl4_mixer.c
+++ b/sound/drivers/opl4/opl4_mixer.c
@@ -47,7 +47,7 @@
 	return value != old_value;
 }
 
-static struct snd_kcontrol_new snd_opl4_controls[] = {
+static const struct snd_kcontrol_new snd_opl4_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "FM Playback Volume",
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c
index e0516e5..f214909 100644
--- a/sound/drivers/opl4/opl4_proc.c
+++ b/sound/drivers/opl4/opl4_proc.c
@@ -76,7 +76,7 @@
 	return count;
 }
 
-static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
+static const struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
 	.open = snd_opl4_mem_proc_open,
 	.release = snd_opl4_mem_proc_release,
 	.read = snd_opl4_mem_proc_read,
diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c
index 03d6202..f59ca66 100644
--- a/sound/drivers/opl4/opl4_seq.c
+++ b/sound/drivers/opl4/opl4_seq.c
@@ -100,7 +100,7 @@
 	return 0;
 }
 
-static struct snd_midi_op opl4_ops = {
+static const struct snd_midi_op opl4_ops = {
 	.note_on =		snd_opl4_note_on,
 	.note_off =		snd_opl4_note_off,
 	.note_terminate =	snd_opl4_terminate_note,
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 7bc1e58..34e2bd5 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -248,7 +248,7 @@
  * Attenuation according to GM recommendations, in -0.375 dB units.
  * table[v] = 40 * log(v / 127) / -0.375
  */
-static unsigned char snd_opl4_volume_table[128] = {
+static const unsigned char snd_opl4_volume_table[128] = {
 	255,224,192,173,160,150,141,134,
 	128,122,117,113,109,105,102, 99,
 	 96, 93, 90, 88, 85, 83, 81, 79,
diff --git a/sound/drivers/pcm-indirect2.c b/sound/drivers/pcm-indirect2.c
deleted file mode 100644
index 4c491d0..0000000
--- a/sound/drivers/pcm-indirect2.c
+++ /dev/null
@@ -1,560 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Helper functions for indirect PCM data transfer to a simple FIFO in
- * hardware (small, no possibility to read "hardware io position",
- * updating position done by interrupt, ...)
- *
- *  Copyright (c) by 2007  Joachim Foerster <JOFT@gmx.de>
- *
- *  Based on "pcm-indirect.h" (alsa-driver-1.0.13) by
- *
- *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *                   Jaroslav Kysela <perex@suse.cz>
- */
-
-/* snd_printk/d() */
-#include <sound/core.h>
-/* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t
- * snd_pcm_period_elapsed() */
-#include <sound/pcm.h>
-
-#include "pcm-indirect2.h"
-
-#ifdef SND_PCM_INDIRECT2_STAT
-/* jiffies */
-#include <linux/jiffies.h>
-
-void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
-			    struct snd_pcm_indirect2 *rec)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int i;
-	int j;
-	int k;
-	int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ;
-
-	snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, "
-		   "irq_occurred: %d\n",
-		   rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured);
-	snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n",
-		   rec->min_multiple);
-	snd_printk(KERN_DEBUG "STAT: firstbytetime: %lu, lastbytetime: %lu, "
-		   "firstzerotime: %lu\n",
-		 rec->firstbytetime, rec->lastbytetime, rec->firstzerotime);
-	snd_printk(KERN_DEBUG "STAT: bytes2hw: %u Bytes => (by runtime->rate) "
-		   "length: %d s\n",
-		 rec->bytes2hw, rec->bytes2hw / 2 / 2 / runtime->rate);
-	snd_printk(KERN_DEBUG "STAT: (by measurement) length: %d => "
-		   "rate: %d Bytes/s = %d Frames/s|Hz\n",
-		   seconds, rec->bytes2hw / seconds,
-		   rec->bytes2hw / 2 / 2 / seconds);
-	snd_printk(KERN_DEBUG
-		   "STAT: zeros2hw: %u = %d ms ~ %d * %d zero copies\n",
-		   rec->zeros2hw, ((rec->zeros2hw / 2 / 2) * 1000) /
-		   runtime->rate,
-		   rec->zeros2hw / (rec->hw_buffer_size / 2),
-		   (rec->hw_buffer_size / 2));
-	snd_printk(KERN_DEBUG "STAT: pointer_calls: %u, lastdifftime: %u\n",
-		   rec->pointer_calls, rec->lastdifftime);
-	snd_printk(KERN_DEBUG "STAT: sw_io: %d, sw_data: %d\n", rec->sw_io,
-		   rec->sw_data);
-	snd_printk(KERN_DEBUG "STAT: byte_sizes[]:\n");
-	k = 0;
-	for (j = 0; j < 8; j++) {
-		for (i = j * 8; i < (j + 1) * 8; i++)
-			if (rec->byte_sizes[i] != 0) {
-				snd_printk(KERN_DEBUG "%u: %u",
-					   i, rec->byte_sizes[i]);
-				k++;
-			}
-		if (((k % 8) == 0) && (k != 0)) {
-			snd_printk(KERN_DEBUG "\n");
-			k = 0;
-		}
-	}
-	snd_printk(KERN_DEBUG "\n");
-	snd_printk(KERN_DEBUG "STAT: zero_sizes[]:\n");
-	for (j = 0; j < 8; j++) {
-		k = 0;
-		for (i = j * 8; i < (j + 1) * 8; i++)
-			if (rec->zero_sizes[i] != 0)
-				snd_printk(KERN_DEBUG "%u: %u",
-					   i, rec->zero_sizes[i]);
-			else
-				k++;
-		if (!k)
-			snd_printk(KERN_DEBUG "\n");
-	}
-	snd_printk(KERN_DEBUG "\n");
-	snd_printk(KERN_DEBUG "STAT: min_adds[]:\n");
-	for (j = 0; j < 8; j++) {
-		if (rec->min_adds[j] != 0)
-			snd_printk(KERN_DEBUG "%u: %u", j, rec->min_adds[j]);
-	}
-	snd_printk(KERN_DEBUG "\n");
-	snd_printk(KERN_DEBUG "STAT: mul_adds[]:\n");
-	for (j = 0; j < 8; j++) {
-		if (rec->mul_adds[j] != 0)
-			snd_printk(KERN_DEBUG "%u: %u", j, rec->mul_adds[j]);
-	}
-	snd_printk(KERN_DEBUG "\n");
-	snd_printk(KERN_DEBUG
-		   "STAT: zero_times_saved: %d, zero_times_notsaved: %d\n",
-		   rec->zero_times_saved, rec->zero_times_notsaved);
-	/* snd_printk(KERN_DEBUG "STAT: zero_times[]\n");
-	i = 0;
-	for (j = 0; j < 3750; j++) {
-		if (rec->zero_times[j] != 0) {
-			snd_printk(KERN_DEBUG "%u: %u", j, rec->zero_times[j]);
-			i++;
-		}
-		if (((i % 8) == 0) && (i != 0))
-			snd_printk(KERN_DEBUG "\n");
-	}
-	snd_printk(KERN_DEBUG "\n"); */
-	return;
-}
-#endif
-
-/*
- * _internal_ helper function for playback/capture transfer function
- */
-static void
-snd_pcm_indirect2_increase_min_periods(struct snd_pcm_substream *substream,
-				       struct snd_pcm_indirect2 *rec,
-				       int isplay, int iscopy,
-				       unsigned int bytes)
-{
-	if (rec->min_periods >= 0) {
-		if (iscopy) {
-			rec->sw_io += bytes;
-			if (rec->sw_io >= rec->sw_buffer_size)
-				rec->sw_io -= rec->sw_buffer_size;
-		} else if (isplay) {
-			/* If application does not write data in multiples of
-			 * a period, move sw_data to the next correctly aligned
-			 * position, so that sw_io can converge to it (in the
-			 * next step).
-			 */
-			if (!rec->check_alignment) {
-				if (rec->bytes2hw %
-				    snd_pcm_lib_period_bytes(substream)) {
-					unsigned bytes2hw_aligned =
-					    (1 +
-					     (rec->bytes2hw /
-					      snd_pcm_lib_period_bytes
-					      (substream))) *
-					    snd_pcm_lib_period_bytes
-					    (substream);
-					rec->sw_data =
-					    bytes2hw_aligned %
-					    rec->sw_buffer_size;
-#ifdef SND_PCM_INDIRECT2_STAT
-					snd_printk(KERN_DEBUG
-						   "STAT: @re-align: aligned "
-						   "bytes2hw to next period "
-						   "size boundary: %d "
-						   "(instead of %d)\n",
-						   bytes2hw_aligned,
-						   rec->bytes2hw);
-					snd_printk(KERN_DEBUG
-						   "STAT: @re-align: sw_data "
-						   "moves to: %d\n",
-						   rec->sw_data);
-#endif
-				}
-				rec->check_alignment = 1;
-			}
-			/* We are at the end and are copying zeros into the
-			 * fifo.
-			 * Now, we have to make sure that sw_io is increased
-			 * until the position of sw_data: Filling the fifo with
-			 * the first zeros means, the last bytes were played.
-			 */
-			if (rec->sw_io != rec->sw_data) {
-				unsigned int diff;
-				if (rec->sw_data > rec->sw_io)
-					diff = rec->sw_data - rec->sw_io;
-				else
-					diff = (rec->sw_buffer_size -
-						rec->sw_io) +
-						rec->sw_data;
-				if (bytes >= diff)
-					rec->sw_io = rec->sw_data;
-				else {
-					rec->sw_io += bytes;
-					if (rec->sw_io >= rec->sw_buffer_size)
-						rec->sw_io -=
-						    rec->sw_buffer_size;
-				}
-			}
-		}
-		rec->min_period_count += bytes;
-		if (rec->min_period_count >= (rec->hw_buffer_size / 2)) {
-			rec->min_periods += (rec->min_period_count /
-					     (rec->hw_buffer_size / 2));
-#ifdef SND_PCM_INDIRECT2_STAT
-			if ((rec->min_period_count /
-			     (rec->hw_buffer_size / 2)) > 7)
-				snd_printk(KERN_DEBUG
-					   "STAT: more than 7 (%d) min_adds "
-					   "at once - too big to save!\n",
-					   (rec->min_period_count /
-					    (rec->hw_buffer_size / 2)));
-			else
-				rec->min_adds[(rec->min_period_count /
-					       (rec->hw_buffer_size / 2))]++;
-#endif
-			rec->min_period_count = (rec->min_period_count %
-						 (rec->hw_buffer_size / 2));
-		}
-	} else if (isplay && iscopy)
-		rec->min_periods = 0;
-}
-
-/*
- * helper function for playback/capture pointer callback
- */
-snd_pcm_uframes_t
-snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream,
-			  struct snd_pcm_indirect2 *rec)
-{
-#ifdef SND_PCM_INDIRECT2_STAT
-	rec->pointer_calls++;
-#endif
-	return bytes_to_frames(substream->runtime, rec->sw_io);
-}
-
-/*
- * _internal_ helper function for playback interrupt callback
- */
-static void
-snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream,
-				    struct snd_pcm_indirect2 *rec,
-				    snd_pcm_indirect2_copy_t copy,
-				    snd_pcm_indirect2_zero_t zero)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
-
-	/* runtime->control->appl_ptr: position where ALSA will write next time
-	 * rec->appl_ptr: position where ALSA was last time
-	 * diff: obviously ALSA wrote that much bytes into the intermediate
-	 * buffer since we checked last time
-	 */
-	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
-
-	if (diff) {
-#ifdef SND_PCM_INDIRECT2_STAT
-		rec->lastdifftime = jiffies;
-#endif
-		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
-			diff += runtime->boundary;
-		/* number of bytes "added" by ALSA increases the number of
-		 * bytes which are ready to "be transferred to HW"/"played"
-		 * Then, set rec->appl_ptr to not count bytes twice next time.
-		 */
-		rec->sw_ready += (int)frames_to_bytes(runtime, diff);
-		rec->appl_ptr = appl_ptr;
-	}
-	if (rec->hw_ready && (rec->sw_ready <= 0)) {
-		unsigned int bytes;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if (rec->firstzerotime == 0) {
-			rec->firstzerotime = jiffies;
-			snd_printk(KERN_DEBUG
-				   "STAT: @firstzerotime: mul_elapsed: %d, "
-				   "min_period_count: %d\n",
-				   rec->mul_elapsed, rec->min_period_count);
-			snd_printk(KERN_DEBUG
-				   "STAT: @firstzerotime: sw_io: %d, "
-				   "sw_data: %d, appl_ptr: %u\n",
-				   rec->sw_io, rec->sw_data,
-				   (unsigned int)appl_ptr);
-		}
-		if ((jiffies - rec->firstzerotime) < 3750) {
-			rec->zero_times[(jiffies - rec->firstzerotime)]++;
-			rec->zero_times_saved++;
-		} else
-			rec->zero_times_notsaved++;
-#endif
-		bytes = zero(substream, rec);
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		rec->zeros2hw += bytes;
-		if (bytes < 64)
-			rec->zero_sizes[bytes]++;
-		else
-			snd_printk(KERN_DEBUG
-				   "STAT: %d zero Bytes copied to hardware at "
-				   "once - too big to save!\n",
-				   bytes);
-#endif
-		snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 0,
-						       bytes);
-		return;
-	}
-	while (rec->hw_ready && (rec->sw_ready > 0)) {
-		/* sw_to_end: max. number of bytes that can be read/take from
-		 * the current position (sw_data) in _one_ step
-		 */
-		unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
-
-		/* bytes: number of bytes we have available (for reading) */
-		unsigned int bytes = rec->sw_ready;
-
-		if (sw_to_end < bytes)
-			bytes = sw_to_end;
-		if (!bytes)
-			break;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if (rec->firstbytetime == 0)
-			rec->firstbytetime = jiffies;
-		rec->lastbytetime = jiffies;
-#endif
-		/* copy bytes from intermediate buffer position sw_data to the
-		 * HW and return number of bytes actually written
-		 * Furthermore, set hw_ready to 0, if the fifo isn't empty
-		 * now => more could be transferred to fifo
-		 */
-		bytes = copy(substream, rec, bytes);
-		rec->bytes2hw += bytes;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if (bytes < 64)
-			rec->byte_sizes[bytes]++;
-		else
-			snd_printk(KERN_DEBUG
-				   "STAT: %d Bytes copied to hardware at once "
-				   "- too big to save!\n",
-				   bytes);
-#endif
-		/* increase sw_data by the number of actually written bytes
-		 * (= number of taken bytes from intermediate buffer)
-		 */
-		rec->sw_data += bytes;
-		if (rec->sw_data == rec->sw_buffer_size)
-			rec->sw_data = 0;
-		/* now sw_data is the position where ALSA is going to write
-		 * in the intermediate buffer next time = position we are going
-		 * to read from next time
-		 */
-
-		snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 1,
-						       bytes);
-
-		/* we read bytes from intermediate buffer, so we need to say
-		 * that the number of bytes ready for transfer are decreased
-		 * now
-		 */
-		rec->sw_ready -= bytes;
-	}
-	return;
-}
-
-/*
- * helper function for playback interrupt routine
- */
-void
-snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream,
-				     struct snd_pcm_indirect2 *rec,
-				     snd_pcm_indirect2_copy_t copy,
-				     snd_pcm_indirect2_zero_t zero)
-{
-#ifdef SND_PCM_INDIRECT2_STAT
-	rec->irq_occured++;
-#endif
-	/* hardware played some bytes, so there is room again (in fifo) */
-	rec->hw_ready = 1;
-
-	/* don't call ack() now, instead call transfer() function directly
-	 * (normally called by ack() )
-	 */
-	snd_pcm_indirect2_playback_transfer(substream, rec, copy, zero);
-
-	if (rec->min_periods >= rec->min_multiple) {
-#ifdef SND_PCM_INDIRECT2_STAT
-		if ((rec->min_periods / rec->min_multiple) > 7)
-			snd_printk(KERN_DEBUG
-				   "STAT: more than 7 (%d) mul_adds - too big "
-				   "to save!\n",
-				   (rec->min_periods / rec->min_multiple));
-		else
-			rec->mul_adds[(rec->min_periods /
-				       rec->min_multiple)]++;
-		rec->mul_elapsed_real += (rec->min_periods /
-					  rec->min_multiple);
-		rec->mul_elapsed++;
-#endif
-		rec->min_periods = (rec->min_periods % rec->min_multiple);
-		snd_pcm_period_elapsed(substream);
-	}
-}
-
-/*
- * _internal_ helper function for capture interrupt callback
- */
-static void
-snd_pcm_indirect2_capture_transfer(struct snd_pcm_substream *substream,
-				   struct snd_pcm_indirect2 *rec,
-				   snd_pcm_indirect2_copy_t copy,
-				   snd_pcm_indirect2_zero_t null)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
-	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
-
-	if (diff) {
-#ifdef SND_PCM_INDIRECT2_STAT
-		rec->lastdifftime = jiffies;
-#endif
-		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
-			diff += runtime->boundary;
-		rec->sw_ready -= frames_to_bytes(runtime, diff);
-		rec->appl_ptr = appl_ptr;
-	}
-	/* if hardware has something, but the intermediate buffer is full
-	 * => skip contents of buffer
-	 */
-	if (rec->hw_ready && (rec->sw_ready >= (int)rec->sw_buffer_size)) {
-		unsigned int bytes;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if (rec->firstzerotime == 0) {
-			rec->firstzerotime = jiffies;
-			snd_printk(KERN_DEBUG "STAT: (capture) "
-				   "@firstzerotime: mul_elapsed: %d, "
-				   "min_period_count: %d\n",
-				   rec->mul_elapsed, rec->min_period_count);
-			snd_printk(KERN_DEBUG "STAT: (capture) "
-				   "@firstzerotime: sw_io: %d, sw_data: %d, "
-				   "appl_ptr: %u\n",
-				   rec->sw_io, rec->sw_data,
-				   (unsigned int)appl_ptr);
-		}
-		if ((jiffies - rec->firstzerotime) < 3750) {
-			rec->zero_times[(jiffies - rec->firstzerotime)]++;
-			rec->zero_times_saved++;
-		} else
-			rec->zero_times_notsaved++;
-#endif
-		bytes = null(substream, rec);
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		rec->zeros2hw += bytes;
-		if (bytes < 64)
-			rec->zero_sizes[bytes]++;
-		else
-			snd_printk(KERN_DEBUG
-				   "STAT: (capture) %d zero Bytes copied to "
-				   "hardware at once - too big to save!\n",
-				   bytes);
-#endif
-		snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 0,
-						       bytes);
-		/* report an overrun */
-		rec->sw_io = SNDRV_PCM_POS_XRUN;
-		return;
-	}
-	while (rec->hw_ready && (rec->sw_ready < (int)rec->sw_buffer_size)) {
-		/* sw_to_end: max. number of bytes that we can write to the
-		 *  intermediate buffer (until it's end)
-		 */
-		size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
-
-		/* bytes: max. number of bytes, which may be copied to the
-		 *  intermediate buffer without overflow (in _one_ step)
-		 */
-		size_t bytes = rec->sw_buffer_size - rec->sw_ready;
-
-		/* limit number of bytes (for transfer) by available room in
-		 * the intermediate buffer
-		 */
-		if (sw_to_end < bytes)
-			bytes = sw_to_end;
-		if (!bytes)
-			break;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if (rec->firstbytetime == 0)
-			rec->firstbytetime = jiffies;
-		rec->lastbytetime = jiffies;
-#endif
-		/* copy bytes from the intermediate buffer (position sw_data)
-		 * to the HW at most and return number of bytes actually copied
-		 * from HW
-		 * Furthermore, set hw_ready to 0, if the fifo is empty now.
-		 */
-		bytes = copy(substream, rec, bytes);
-		rec->bytes2hw += bytes;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if (bytes < 64)
-			rec->byte_sizes[bytes]++;
-		else
-			snd_printk(KERN_DEBUG
-				   "STAT: (capture) %d Bytes copied to "
-				   "hardware at once - too big to save!\n",
-				   bytes);
-#endif
-		/* increase sw_data by the number of actually copied bytes from
-		 * HW
-		 */
-		rec->sw_data += bytes;
-		if (rec->sw_data == rec->sw_buffer_size)
-			rec->sw_data = 0;
-
-		snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 1,
-						       bytes);
-
-		/* number of bytes in the intermediate buffer, which haven't
-		 * been fetched by ALSA yet.
-		 */
-		rec->sw_ready += bytes;
-	}
-	return;
-}
-
-/*
- * helper function for capture interrupt routine
- */
-void
-snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream,
-				    struct snd_pcm_indirect2 *rec,
-				    snd_pcm_indirect2_copy_t copy,
-				    snd_pcm_indirect2_zero_t null)
-{
-#ifdef SND_PCM_INDIRECT2_STAT
-	rec->irq_occured++;
-#endif
-	/* hardware recorded some bytes, so there is something to read from the
-	 * record fifo:
-	 */
-	rec->hw_ready = 1;
-
-	/* don't call ack() now, instead call transfer() function directly
-	 * (normally called by ack() )
-	 */
-	snd_pcm_indirect2_capture_transfer(substream, rec, copy, null);
-
-	if (rec->min_periods >= rec->min_multiple) {
-
-#ifdef SND_PCM_INDIRECT2_STAT
-		if ((rec->min_periods / rec->min_multiple) > 7)
-			snd_printk(KERN_DEBUG
-				   "STAT: more than 7 (%d) mul_adds - "
-				   "too big to save!\n",
-				   (rec->min_periods / rec->min_multiple));
-		else
-			rec->mul_adds[(rec->min_periods /
-				       rec->min_multiple)]++;
-		rec->mul_elapsed_real += (rec->min_periods /
-					  rec->min_multiple);
-		rec->mul_elapsed++;
-#endif
-		rec->min_periods = (rec->min_periods % rec->min_multiple);
-		snd_pcm_period_elapsed(substream);
-	}
-}
diff --git a/sound/drivers/pcm-indirect2.h b/sound/drivers/pcm-indirect2.h
deleted file mode 100644
index 355ce76..0000000
--- a/sound/drivers/pcm-indirect2.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Helper functions for indirect PCM data transfer to a simple FIFO in
- * hardware (small, no possibility to read "hardware io position",
- * updating position done by interrupt, ...)
- *
- *  Copyright (c) by 2007  Joachim Foerster <JOFT@gmx.de>
- *
- *  Based on "pcm-indirect.h" (alsa-driver-1.0.13) by
- *
- *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *                   Jaroslav Kysela <perex@suse.cz>
- */
-
-#ifndef __SOUND_PCM_INDIRECT2_H
-#define __SOUND_PCM_INDIRECT2_H
-
-/* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t */
-#include <sound/pcm.h>
-
-/* Debug options for code which may be removed completely in a final version */
-#ifdef CONFIG_SND_DEBUG
-#define SND_PCM_INDIRECT2_STAT    /* turn on some "statistics" about the
-				   * process of copying bytes from the
-				   * intermediate buffer to the hardware
-				   * fifo and the other way round
-				   */
-#endif
-
-struct snd_pcm_indirect2 {
-	unsigned int hw_buffer_size;  /* Byte size of hardware buffer */
-	int hw_ready;		      /* playback: 1 = hw fifo has room left,
-				       * 0 = hw fifo is full
-				       */
-	unsigned int min_multiple;
-	int min_periods;	      /* counts number of min. periods until
-				       * min_multiple is reached
-				       */
-	int min_period_count;	      /* counts bytes to count number of
-				       * min. periods
-				       */
-
-	unsigned int sw_buffer_size;  /* Byte size of software buffer */
-
-	/* sw_data: position in intermediate buffer, where we will read (or
-	 *          write) from/to next time (to transfer data to/from HW)
-	 */
-	unsigned int sw_data;         /* Offset to next dst (or src) in sw
-				       * ring buffer
-				       */
-	/* easiest case (playback):
-	 * sw_data is nearly the same as ~ runtime->control->appl_ptr, with the
-	 * exception that sw_data is "behind" by the number if bytes ALSA wrote
-	 * to the intermediate buffer last time.
-	 * A call to ack() callback synchronizes both indirectly.
-	 */
-
-	/* We have no real sw_io pointer here. Usually sw_io is pointing to the
-	 * current playback/capture position _inside_ the hardware. Devices
-	 * with plain FIFOs often have no possibility to publish this position.
-	 * So we say: if sw_data is updated, that means bytes were copied to
-	 * the hardware, we increase sw_io by that amount, because there have
-	 * to be as much bytes which were played. So sw_io will stay behind
-	 * sw_data all the time and has to converge to sw_data at the end of
-	 * playback.
-	 */
-	unsigned int sw_io;           /* Current software pointer in bytes */
-
-	/* sw_ready: number of bytes ALSA copied to the intermediate buffer, so
-	 * it represents the number of bytes which wait for transfer to the HW
-	 */
-	int sw_ready;		  /* Bytes ready to be transferred to/from hw */
-
-	/* appl_ptr: last known position of ALSA (where ALSA is going to write
-	 * next time into the intermediate buffer
-	 */
-	snd_pcm_uframes_t appl_ptr;   /* Last seen appl_ptr */
-
-	unsigned int bytes2hw;
-	int check_alignment;
-
-#ifdef SND_PCM_INDIRECT2_STAT
-	unsigned int zeros2hw;
-	unsigned int mul_elapsed;
-	unsigned int mul_elapsed_real;
-	unsigned long firstbytetime;
-	unsigned long lastbytetime;
-	unsigned long firstzerotime;
-	unsigned int byte_sizes[64];
-	unsigned int zero_sizes[64];
-	unsigned int min_adds[8];
-	unsigned int mul_adds[8];
-	unsigned int zero_times[3750];	/* = 15s */
-	unsigned int zero_times_saved;
-	unsigned int zero_times_notsaved;
-	unsigned int irq_occured;
-	unsigned int pointer_calls;
-	unsigned int lastdifftime;
-#endif
-};
-
-typedef size_t (*snd_pcm_indirect2_copy_t) (struct snd_pcm_substream *substream,
-					   struct snd_pcm_indirect2 *rec,
-					   size_t bytes);
-typedef size_t (*snd_pcm_indirect2_zero_t) (struct snd_pcm_substream *substream,
-					   struct snd_pcm_indirect2 *rec);
-
-#ifdef SND_PCM_INDIRECT2_STAT
-void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
-				   struct snd_pcm_indirect2 *rec);
-#endif
-
-snd_pcm_uframes_t
-snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream,
-			  struct snd_pcm_indirect2 *rec);
-void
-snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream,
-				     struct snd_pcm_indirect2 *rec,
-				     snd_pcm_indirect2_copy_t copy,
-				     snd_pcm_indirect2_zero_t zero);
-void
-snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream,
-				    struct snd_pcm_indirect2 *rec,
-				    snd_pcm_indirect2_copy_t copy,
-				    snd_pcm_indirect2_zero_t null);
-
-#endif /* __SOUND_PCM_INDIRECT2_H */
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 14aacd8..fd79e57 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -43,7 +43,7 @@
 
 static int snd_pcsp_create(struct snd_card *card)
 {
-	static struct snd_device_ops ops = { };
+	static const struct snd_device_ops ops = { };
 	unsigned int resolution = hrtimer_resolution;
 	int err, div, min_div, order;
 
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 8f0f05b..ed40d0f 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -23,10 +23,10 @@
 #define DMIX_WANTS_S16	1
 
 /*
- * Call snd_pcm_period_elapsed in a tasklet
+ * Call snd_pcm_period_elapsed in a work
  * This avoids spinlock messes and long-running irq contexts
  */
-static void pcsp_call_pcm_elapsed(unsigned long priv)
+static void pcsp_call_pcm_elapsed(struct work_struct *work)
 {
 	if (atomic_read(&pcsp_chip.timer_active)) {
 		struct snd_pcm_substream *substream;
@@ -36,7 +36,7 @@
 	}
 }
 
-static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0);
+static DECLARE_WORK(pcsp_pcm_work, pcsp_call_pcm_elapsed);
 
 /* write the port and returns the next expire time in ns;
  * called at the trigger-start and in hrtimer callback
@@ -119,11 +119,9 @@
 	if (periods_elapsed) {
 		chip->period_ptr += periods_elapsed * period_bytes;
 		chip->period_ptr %= buffer_bytes;
+		queue_work(system_highpri_wq, &pcsp_pcm_work);
 	}
 	spin_unlock_irqrestore(&chip->substream_lock, flags);
-
-	if (periods_elapsed)
-		tasklet_schedule(&pcsp_pcm_tasklet);
 }
 
 enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
@@ -196,7 +194,7 @@
 	pcsp_stop_playing(chip);
 	local_irq_enable();
 	hrtimer_cancel(&chip->timer);
-	tasklet_kill(&pcsp_pcm_tasklet);
+	cancel_work_sync(&pcsp_pcm_work);
 }
 
 static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
@@ -214,12 +212,7 @@
 				       struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
-	int err;
 	pcsp_sync_stop(chip);
-	err = snd_pcm_lib_malloc_pages(substream,
-				      params_buffer_bytes(hw_params));
-	if (err < 0)
-		return err;
 	return 0;
 }
 
@@ -230,7 +223,7 @@
 	printk(KERN_INFO "PCSP: hw_free called\n");
 #endif
 	pcsp_sync_stop(chip);
-	return snd_pcm_lib_free_pages(substream);
+	return 0;
 }
 
 static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
@@ -327,7 +320,6 @@
 static const struct snd_pcm_ops snd_pcsp_playback_ops = {
 	.open = snd_pcsp_playback_open,
 	.close = snd_pcsp_playback_close,
-	.ioctl = snd_pcm_lib_ioctl,
 	.hw_params = snd_pcsp_playback_hw_params,
 	.hw_free = snd_pcsp_playback_hw_free,
 	.prepare = snd_pcsp_playback_prepare,
@@ -350,11 +342,11 @@
 	chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
 	strcpy(chip->pcm->name, "pcsp");
 
-	snd_pcm_lib_preallocate_pages_for_all(chip->pcm,
-					      SNDRV_DMA_TYPE_CONTINUOUS,
-					      snd_dma_continuous_data
-					      (GFP_KERNEL), PCSP_BUFFER_SIZE,
-					      PCSP_BUFFER_SIZE);
+	snd_pcm_set_managed_buffer_all(chip->pcm,
+				       SNDRV_DMA_TYPE_CONTINUOUS,
+				       NULL,
+				       PCSP_BUFFER_SIZE,
+				       PCSP_BUFFER_SIZE);
 
 	return 0;
 }
diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c
index be29904..da33e5b 100644
--- a/sound/drivers/pcsp/pcsp_mixer.c
+++ b/sound/drivers/pcsp/pcsp_mixer.c
@@ -120,17 +120,17 @@
 	.put =		pcsp_##ctl_type##_put, \
 }
 
-static struct snd_kcontrol_new snd_pcsp_controls_pcm[] = {
+static const struct snd_kcontrol_new snd_pcsp_controls_pcm[] = {
 	PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
 	PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
 };
 
-static struct snd_kcontrol_new snd_pcsp_controls_spkr[] = {
+static const struct snd_kcontrol_new snd_pcsp_controls_spkr[] = {
 	PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"),
 };
 
 static int snd_pcsp_ctls_add(struct snd_pcsp *chip,
-			     struct snd_kcontrol_new *ctls, int num)
+			     const struct snd_kcontrol_new *ctls, int num)
 {
 	int i, err;
 	struct snd_card *card = chip->card;
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index ecefa7c..c876cf9 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -457,7 +457,7 @@
 
 	/* Set for RXDATA0 where no damage will be done. */
 	/* 5 */
-	parport_write_control(p, RXDATA0 + STROBE);	/* Write Strobe=1 to command reg. */
+	parport_write_control(p, RXDATA0 | STROBE);	/* Write Strobe=1 to command reg. */
 
 	/* 6 */
 	if ((parport_read_status(p) & ESTB) != ESTB)
@@ -467,7 +467,7 @@
 	parport_write_control(p, 0);	/* Reset Strobe=0. */
 
 	/* Check if Tx circuitry is functioning properly.  If initialized 
-	 * unit TxEmpty is false, send out char and see if if goes true.
+	 * unit TxEmpty is false, send out char and see if it goes true.
 	 */
 	/* 8 */
 	parport_write_control(p, TXDATA0);	/* Tx channel 0, strobe off. */
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 4775f1b..3947f08 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -42,7 +42,7 @@
 #define SNDRV_SERIAL_MS124W_MB 3   /* Midiator MS-124W in M/B mode */
 #define SNDRV_SERIAL_GENERIC 4     /* Generic Interface */
 #define SNDRV_SERIAL_MAX_ADAPTOR SNDRV_SERIAL_GENERIC
-static char *adaptor_names[] = {
+static const char * const adaptor_names[] = {
 	"Soundcanvas",
         "MS-124T",
 	"MS-124W S/A",
@@ -777,7 +777,7 @@
 				int droponfull,
 				struct snd_uart16550 **ruart)
 {
-	static struct snd_device_ops ops = {
+	static const struct snd_device_ops ops = {
 		.dev_free =	snd_uart16550_dev_free,
 	};
 	struct snd_uart16550 *uart;
diff --git a/sound/drivers/vx/vx_cmd.c b/sound/drivers/vx/vx_cmd.c
index 77ae59a..b0970a0 100644
--- a/sound/drivers/vx/vx_cmd.c
+++ b/sound/drivers/vx/vx_cmd.c
@@ -15,7 +15,7 @@
 /*
  * Array of DSP commands
  */
-static struct vx_cmd_info vx_dsp_cmds[] = {
+static const struct vx_cmd_info vx_dsp_cmds[] = {
 [CMD_VERSION] =			{ 0x010000, 2, RMH_SSIZE_FIXED, 1 },
 [CMD_SUPPORTED] =		{ 0x020000, 1, RMH_SSIZE_FIXED, 2 },
 [CMD_TEST_IT] =			{ 0x040000, 1, RMH_SSIZE_FIXED, 1 },
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 6bbc2a4..d5c65ca 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -39,7 +39,7 @@
 int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time)
 {
 	unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
-	static char *reg_names[VX_REG_MAX] = {
+	static const char * const reg_names[VX_REG_MAX] = {
 		"ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL",
 		"DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ",
 		"ACQ", "BIT0", "BIT1", "MIC0", "MIC1", "MIC2",
@@ -511,8 +511,9 @@
 	/* The start on time code conditions are filled (ie the time code
 	 * received by the board is equal to one of those given to it).
 	 */
-	if (events & TIME_CODE_EVENT_PENDING)
+	if (events & TIME_CODE_EVENT_PENDING) {
 		; /* so far, nothing to do yet */
+	}
 
 	/* The frequency has changed on the board (UER mode). */
 	if (events & FREQUENCY_CHANGE_EVENT_PENDING)
@@ -588,17 +589,17 @@
 static void vx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
 	struct vx_core *chip = entry->private_data;
-	static char *audio_src_vxp[] = { "Line", "Mic", "Digital" };
-	static char *audio_src_vx2[] = { "Analog", "Analog", "Digital" };
-	static char *clock_mode[] = { "Auto", "Internal", "External" };
-	static char *clock_src[] = { "Internal", "External" };
-	static char *uer_type[] = { "Consumer", "Professional", "Not Present" };
+	static const char * const audio_src_vxp[] = { "Line", "Mic", "Digital" };
+	static const char * const audio_src_vx2[] = { "Analog", "Analog", "Digital" };
+	static const char * const clock_mode[] = { "Auto", "Internal", "External" };
+	static const char * const clock_src[] = { "Internal", "External" };
+	static const char * const uer_type[] = { "Consumer", "Professional", "Not Present" };
 	
 	snd_iprintf(buffer, "%s\n", chip->card->longname);
 	snd_iprintf(buffer, "Xilinx Firmware: %s\n",
-		    chip->chip_status & VX_STAT_XILINX_LOADED ? "Loaded" : "No");
+		    (chip->chip_status & VX_STAT_XILINX_LOADED) ? "Loaded" : "No");
 	snd_iprintf(buffer, "Device Initialized: %s\n",
-		    chip->chip_status & VX_STAT_DEVICE_INIT ? "Yes" : "No");
+		    (chip->chip_status & VX_STAT_DEVICE_INIT) ? "Yes" : "No");
 	snd_iprintf(buffer, "DSP audio info:");
 	if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME)
 		snd_iprintf(buffer, " realtime");
@@ -765,8 +766,9 @@
  *
  * return the instance pointer if successful, NULL in error.
  */
-struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
-			      struct snd_vx_ops *ops,
+struct vx_core *snd_vx_create(struct snd_card *card,
+			      const struct snd_vx_hardware *hw,
+			      const struct snd_vx_ops *ops,
 			      int extra_size)
 {
 	struct vx_core *chip;
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index f0d31b0..01baa6d 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -32,7 +32,7 @@
 
 int snd_vx_setup_firmware(struct vx_core *chip)
 {
-	static char *fw_files[VX_TYPE_NUMS][4] = {
+	static const char * const fw_files[VX_TYPE_NUMS][4] = {
 		[VX_TYPE_BOARD] = {
 			NULL, "x1_1_vx2.xlx", "bd56002.boot", "l_1_vx2.d56",
 		},
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index b17c67b..13099f8 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -961,7 +961,7 @@
 		return err;
 	/* VU, peak, saturation meters */
 	for (c = 0; c < 2; c++) {
-		static char *dir[2] = { "Output", "Input" };
+		static const char * const dir[2] = { "Output", "Input" };
 		for (i = 0; i < chip->hw->num_ins; i++) {
 			int val = (i * 2) | (c << 8);
 			if (c == 1) {
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 4705c50..3d2e3bc 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -60,7 +60,6 @@
 	*buf++ = vx_inb(chip, RXL);
 	if (++offset >= pipe->buffer_bytes) {
 		offset = 0;
-		buf = (unsigned char *)runtime->dma_area;
 	}
 	pipe->hw_ptr = offset;
 }
@@ -530,7 +529,6 @@
 		err = vx_alloc_pipe(chip, 0, audio, 2, &pipe); /* stereo playback */
 		if (err < 0)
 			return err;
-		chip->playback_pipes[audio] = pipe;
 	}
 	/* open for playback */
 	pipe->references++;
@@ -773,24 +771,6 @@
 }
 
 /*
- * vx_pcm_hw_params - hw_params callback for playback and capture
- */
-static int vx_pcm_hw_params(struct snd_pcm_substream *subs,
-				     struct snd_pcm_hw_params *hw_params)
-{
-	return snd_pcm_lib_alloc_vmalloc_32_buffer
-					(subs, params_buffer_bytes(hw_params));
-}
-
-/*
- * vx_pcm_hw_free - hw_free callback for playback and capture
- */
-static int vx_pcm_hw_free(struct snd_pcm_substream *subs)
-{
-	return snd_pcm_lib_free_vmalloc_buffer(subs);
-}
-
-/*
  * vx_pcm_prepare - prepare callback for playback and capture
  */
 static int vx_pcm_prepare(struct snd_pcm_substream *subs)
@@ -861,13 +841,9 @@
 static const struct snd_pcm_ops vx_pcm_playback_ops = {
 	.open =		vx_pcm_playback_open,
 	.close =	vx_pcm_playback_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	vx_pcm_hw_params,
-	.hw_free =	vx_pcm_hw_free,
 	.prepare =	vx_pcm_prepare,
 	.trigger =	vx_pcm_trigger,
 	.pointer =	vx_pcm_playback_pointer,
-	.page =		snd_pcm_lib_get_vmalloc_page,
 };
 
 
@@ -1082,13 +1058,9 @@
 static const struct snd_pcm_ops vx_pcm_capture_ops = {
 	.open =		vx_pcm_capture_open,
 	.close =	vx_pcm_capture_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	vx_pcm_hw_params,
-	.hw_free =	vx_pcm_hw_free,
 	.prepare =	vx_pcm_prepare,
 	.trigger =	vx_pcm_trigger,
 	.pointer =	vx_pcm_capture_pointer,
-	.page =		snd_pcm_lib_get_vmalloc_page,
 };
 
 
@@ -1233,6 +1205,9 @@
 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &vx_pcm_playback_ops);
 		if (ins)
 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops);
+		snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
+					       snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32),
+					       0, 0);
 
 		pcm->private_data = chip;
 		pcm->private_free = snd_vx_pcm_free;