Skip to content

Commit acdebd8

Browse files
takaswietiwai
authored andcommitted
ALSA: fireface: implement message parser for Fireface 400
This commit implements message parser for Fireface 400 to pass data of knob control to user space. The parser has FIFO which can store maximum 32 events without no overrun detection since it doesn't matter to lose the event. Signed-off-by: Takashi Sakamoto <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent c31909f commit acdebd8

File tree

1 file changed

+137
-6
lines changed

1 file changed

+137
-6
lines changed

sound/firewire/fireface/ff-protocol-former.c

Lines changed: 137 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,23 @@ static void parse_midi_msg(struct snd_ff *ff, u32 quad, unsigned int port)
545545
}
546546
}
547547

548-
#define FF400_MSG_FLAG_IS_MIDI_PORT_0 0x00000100
549-
#define FF400_MSG_MASK_MIDI_PORT_0 0x000000ff
550-
#define FF400_MSG_FLAG_IS_MIDI_PORT_1 0x01000000
551-
#define FF400_MSG_MASK_MIDI_PORT_1 0x00ff0000
548+
#define FF400_QUEUE_SIZE 32
549+
550+
struct ff400_msg_parser {
551+
struct {
552+
u32 msg;
553+
u32 tstamp;
554+
} msgs[FF400_QUEUE_SIZE];
555+
size_t push_pos;
556+
size_t pull_pos;
557+
};
558+
559+
static bool ff400_has_msg(struct snd_ff *ff)
560+
{
561+
struct ff400_msg_parser *parser = ff->msg_parser;
562+
563+
return (parser->push_pos != parser->pull_pos);
564+
}
552565

553566
// For Fireface 400, lower 4 bytes of destination address is configured by bit
554567
// flag in quadlet register (little endian) at 0x'0000'801'0051c. Drivers can
@@ -569,22 +582,140 @@ static void parse_midi_msg(struct snd_ff *ff, u32 quad, unsigned int port)
569582
// input attenuation. This driver allocates destination address with '0000'0000
570583
// in its lower offset and expects userspace application to configure the
571584
// register for it.
585+
586+
// When the message is for signal level operation, the upper 4 bits in MSB expresses the pair of
587+
// stereo physical port.
588+
// - 0: Microphone input 0/1
589+
// - 1: Line input 0/1
590+
// - [2-4]: Line output 0-5
591+
// - 5: Headphone output 0/1
592+
// - 6: S/PDIF output 0/1
593+
// - [7-10]: ADAT output 0-7
594+
//
595+
// The value of signal level can be detected by mask of 0x00fffc00. For signal level of microphone
596+
// input:
597+
//
598+
// - 0: 0.0 dB
599+
// - 10: +10.0 dB
600+
// - 11: +11.0 dB
601+
// - 12: +12.0 dB
602+
// - ...
603+
// - 63: +63.0 dB:
604+
// - 64: +64.0 dB:
605+
// - 65: +65.0 dB:
606+
//
607+
// For signal level of line input:
608+
//
609+
// - 0: 0.0 dB
610+
// - 1: +0.5 dB
611+
// - 2: +1.0 dB
612+
// - 3: +1.5 dB
613+
// - ...
614+
// - 34: +17.0 dB:
615+
// - 35: +17.5 dB:
616+
// - 36: +18.0 dB:
617+
//
618+
// For signal level of any type of output:
619+
//
620+
// - 63: -infinite
621+
// - 62: -58.0 dB
622+
// - 61: -56.0 dB
623+
// - 60: -54.0 dB
624+
// - 59: -53.0 dB
625+
// - 58: -52.0 dB
626+
// - ...
627+
// - 7: -1.0 dB
628+
// - 6: 0.0 dB
629+
// - 5: +1.0 dB
630+
// - ...
631+
// - 2: +4.0 dB
632+
// - 1: +5.0 dB
633+
// - 0: +6.0 dB
634+
//
635+
// When the message is not for signal level operation, it's for MIDI bytes. When matching to
636+
// FF400_MSG_FLAG_IS_MIDI_PORT_0, one MIDI byte can be detected by mask of 0x000000ff. When
637+
// matching to FF400_MSG_FLAG_IS_MIDI_PORT_1, one MIDI byte can be detected by mask of 0x00ff0000.
638+
#define FF400_MSG_FLAG_IS_SIGNAL_LEVEL 0x04000000
639+
#define FF400_MSG_FLAG_IS_RIGHT_CHANNEL 0x08000000
640+
#define FF400_MSG_FLAG_IS_STEREO_PAIRED 0x02000000
641+
#define FF400_MSG_MASK_STEREO_PAIR 0xf0000000
642+
#define FF400_MSG_MASK_SIGNAL_LEVEL 0x00fffc00
643+
#define FF400_MSG_FLAG_IS_MIDI_PORT_0 0x00000100
644+
#define FF400_MSG_MASK_MIDI_PORT_0 0x000000ff
645+
#define FF400_MSG_FLAG_IS_MIDI_PORT_1 0x01000000
646+
#define FF400_MSG_MASK_MIDI_PORT_1 0x00ff0000
647+
572648
static void ff400_handle_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,
573649
size_t length, u32 tstamp)
574650
{
651+
bool need_hwdep_wake_up = false;
575652
int i;
576653

577654
for (i = 0; i < length / 4; i++) {
578655
u32 quad = le32_to_cpu(buf[i]);
579656

580-
if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_0)
657+
if (quad & FF400_MSG_FLAG_IS_SIGNAL_LEVEL) {
658+
struct ff400_msg_parser *parser = ff->msg_parser;
659+
660+
parser->msgs[parser->push_pos].msg = quad;
661+
parser->msgs[parser->push_pos].tstamp = tstamp;
662+
++parser->push_pos;
663+
if (parser->push_pos >= FF400_QUEUE_SIZE)
664+
parser->push_pos = 0;
665+
666+
need_hwdep_wake_up = true;
667+
} else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_0) {
581668
parse_midi_msg(ff, quad, 0);
582-
else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_1)
669+
} else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_1) {
583670
parse_midi_msg(ff, quad, 1);
671+
}
584672
}
673+
674+
if (need_hwdep_wake_up)
675+
wake_up(&ff->hwdep_wait);
676+
}
677+
678+
static long ff400_copy_msg_to_user(struct snd_ff *ff, char __user *buf, long count)
679+
{
680+
struct ff400_msg_parser *parser = ff->msg_parser;
681+
u32 type = SNDRV_FIREWIRE_EVENT_FF400_MESSAGE;
682+
long consumed = 0;
683+
684+
if (count < 8)
685+
return 0;
686+
687+
spin_unlock_irq(&ff->lock);
688+
689+
if (copy_to_user(buf, &type, sizeof(type)))
690+
return -EFAULT;
691+
692+
spin_lock_irq(&ff->lock);
693+
694+
count -= sizeof(type);
695+
consumed += sizeof(type);
696+
697+
while (count >= sizeof(*parser->msgs) && parser->pull_pos != parser->push_pos) {
698+
spin_unlock_irq(&ff->lock);
699+
700+
if (copy_to_user(buf + consumed, parser->msgs + parser->pull_pos,
701+
sizeof(*parser->msgs)))
702+
return -EFAULT;
703+
704+
spin_lock_irq(&ff->lock);
705+
++parser->pull_pos;
706+
if (parser->pull_pos >= FF400_QUEUE_SIZE)
707+
parser->pull_pos = 0;
708+
count -= sizeof(*parser->msgs);
709+
consumed += sizeof(*parser->msgs);
710+
}
711+
712+
return consumed;
585713
}
586714

587715
const struct snd_ff_protocol snd_ff_protocol_ff400 = {
716+
.msg_parser_size = sizeof(struct ff400_msg_parser),
717+
.has_msg = ff400_has_msg,
718+
.copy_msg_to_user = ff400_copy_msg_to_user,
588719
.handle_msg = ff400_handle_msg,
589720
.fill_midi_msg = former_fill_midi_msg,
590721
.get_clock = former_get_clock,

0 commit comments

Comments
 (0)