ALSA: sb: Convert to the new PCM ops

Replace the copy and the silence ops with the new PCM ops.
For avoiding the code redundancy, slightly hackish macros are
introduced.

Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2017-05-10 20:34:45 +02:00
parent a6970bb1dd
commit 4b83eff81c

View File

@ -422,121 +422,148 @@ do { \
return -EAGAIN;\ return -EAGAIN;\
} while (0) } while (0)
enum {
COPY_USER, COPY_KERNEL, FILL_SILENCE,
};
#define GET_VAL(sval, buf, mode) \
do { \
switch (mode) { \
case FILL_SILENCE: \
sval = 0; \
break; \
case COPY_KERNEL: \
sval = *buf++; \
break; \
default: \
if (get_user(sval, (unsigned short __user *)buf)) \
return -EFAULT; \
buf++; \
break; \
} \
} while (0)
#ifdef USE_NONINTERLEAVE #ifdef USE_NONINTERLEAVE
#define LOOP_WRITE(rec, offset, _buf, count, mode) \
do { \
struct snd_emu8000 *emu = (rec)->emu; \
unsigned short *buf = (unsigned short *)(_buf); \
snd_emu8000_write_wait(emu, 1); \
EMU8000_SMALW_WRITE(emu, offset); \
while (count > 0) { \
unsigned short sval; \
CHECK_SCHEDULER(); \
GET_VAL(sval, buf, mode); \
EMU8000_SMLD_WRITE(emu, sval); \
count--; \
} \
} while (0)
/* copy one channel block */ /* copy one channel block */
static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned short *buf, int count) static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
int voice, unsigned long pos,
void __user *src, unsigned long count)
{ {
EMU8000_SMALW_WRITE(emu, offset); struct snd_emu8k_pcm *rec = subs->runtime->private_data;
while (count > 0) {
unsigned short sval; /* convert to word unit */
CHECK_SCHEDULER(); pos = (pos << 1) + rec->loop_start[voice];
if (get_user(sval, buf)) count <<= 1;
return -EFAULT; LOOP_WRITE(rec, pos, src, count, COPY_UESR);
EMU8000_SMLD_WRITE(emu, sval);
buf++;
count--;
}
return 0; return 0;
} }
static int emu8k_pcm_copy(struct snd_pcm_substream *subs, static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs,
int voice, int voice, unsigned long pos,
snd_pcm_uframes_t pos, void *src, unsigned long count)
void *src,
snd_pcm_uframes_t count)
{ {
struct snd_emu8k_pcm *rec = subs->runtime->private_data; struct snd_emu8k_pcm *rec = subs->runtime->private_data;
struct snd_emu8000 *emu = rec->emu;
snd_emu8000_write_wait(emu, 1); /* convert to word unit */
return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, pos = (pos << 1) + rec->loop_start[voice];
count); count <<= 1;
LOOP_WRITE(rec, pos, src, count, COPY_KERNEL);
return 0;
} }
/* make a channel block silence */ /* make a channel block silence */
static int emu8k_silence_block(struct snd_emu8000 *emu, int offset, int count) static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
int voice, unsigned long pos, unsigned long count)
{ {
EMU8000_SMALW_WRITE(emu, offset); struct snd_emu8k_pcm *rec = subs->runtime->private_data;
while (count > 0) {
CHECK_SCHEDULER(); /* convert to word unit */
EMU8000_SMLD_WRITE(emu, 0); pos = (pos << 1) + rec->loop_start[voice];
count--; count <<= 1;
} LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE);
return 0; return 0;
} }
static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
int voice,
snd_pcm_uframes_t pos,
snd_pcm_uframes_t count)
{
struct snd_emu8k_pcm *rec = subs->runtime->private_data;
struct snd_emu8000 *emu = rec->emu;
snd_emu8000_write_wait(emu, 1);
return emu8k_silence_block(emu, pos + rec->loop_start[voice], count);
}
#else /* interleave */ #else /* interleave */
#define LOOP_WRITE(rec, pos, _buf, count, mode) \
do { \
struct snd_emu8000 *emu = rec->emu; \
unsigned short *buf = (unsigned short *)(_buf); \
snd_emu8000_write_wait(emu, 1); \
EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); \
if (rec->voices > 1) \
EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); \
while (count > 0) { \
unsigned short sval; \
CHECK_SCHEDULER(); \
GET_VAL(sval, buf, mode); \
EMU8000_SMLD_WRITE(emu, sval); \
if (rec->voices > 1) { \
CHECK_SCHEDULER(); \
GET_VAL(sval, buf, mode); \
EMU8000_SMRD_WRITE(emu, sval); \
} \
count--; \
} \
} while (0)
/* /*
* copy the interleaved data can be done easily by using * copy the interleaved data can be done easily by using
* DMA "left" and "right" channels on emu8k engine. * DMA "left" and "right" channels on emu8k engine.
*/ */
static int emu8k_pcm_copy(struct snd_pcm_substream *subs, static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
int voice, int voice, unsigned long pos,
snd_pcm_uframes_t pos, void __user *src, unsigned long count)
void __user *src,
snd_pcm_uframes_t count)
{ {
struct snd_emu8k_pcm *rec = subs->runtime->private_data; struct snd_emu8k_pcm *rec = subs->runtime->private_data;
struct snd_emu8000 *emu = rec->emu;
unsigned short __user *buf = src;
snd_emu8000_write_wait(emu, 1); /* convert to frames */
EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); pos = bytes_to_frames(subs->runtime, pos);
if (rec->voices > 1) count = bytes_to_frames(subs->runtime, count);
EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); LOOP_WRITE(rec, pos, src, count, COPY_USER);
return 0;
}
while (count-- > 0) { static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs,
unsigned short sval; int voice, unsigned long pos,
CHECK_SCHEDULER(); void *src, unsigned long count)
if (get_user(sval, buf)) {
return -EFAULT; struct snd_emu8k_pcm *rec = subs->runtime->private_data;
EMU8000_SMLD_WRITE(emu, sval);
buf++; /* convert to frames */
if (rec->voices > 1) { pos = bytes_to_frames(subs->runtime, pos);
CHECK_SCHEDULER(); count = bytes_to_frames(subs->runtime, count);
if (get_user(sval, buf)) LOOP_WRITE(rec, pos, src, count, COPY_KERNEL);
return -EFAULT;
EMU8000_SMRD_WRITE(emu, sval);
buf++;
}
}
return 0; return 0;
} }
static int emu8k_pcm_silence(struct snd_pcm_substream *subs, static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
int voice, int voice, unsigned long pos, unsigned long count)
snd_pcm_uframes_t pos,
snd_pcm_uframes_t count)
{ {
struct snd_emu8k_pcm *rec = subs->runtime->private_data; struct snd_emu8k_pcm *rec = subs->runtime->private_data;
struct snd_emu8000 *emu = rec->emu;
snd_emu8000_write_wait(emu, 1); /* convert to frames */
EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos); pos = bytes_to_frames(subs->runtime, pos);
if (rec->voices > 1) count = bytes_to_frames(subs->runtime, count);
EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos); LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE);
while (count-- > 0) {
CHECK_SCHEDULER();
EMU8000_SMLD_WRITE(emu, 0);
if (rec->voices > 1) {
CHECK_SCHEDULER();
EMU8000_SMRD_WRITE(emu, 0);
}
}
return 0; return 0;
} }
#endif #endif
@ -652,8 +679,9 @@ static struct snd_pcm_ops emu8k_pcm_ops = {
.prepare = emu8k_pcm_prepare, .prepare = emu8k_pcm_prepare,
.trigger = emu8k_pcm_trigger, .trigger = emu8k_pcm_trigger,
.pointer = emu8k_pcm_pointer, .pointer = emu8k_pcm_pointer,
.copy = emu8k_pcm_copy, .copy_user = emu8k_pcm_copy,
.silence = emu8k_pcm_silence, .copy_kernel = emu8k_pcm_copy_kernel,
.fill_silence = emu8k_pcm_silence,
}; };