253 lines
5.1 KiB
C
253 lines
5.1 KiB
C
/*
|
|
* ff-proc.c - a part of driver for RME Fireface series
|
|
*
|
|
* Copyright (c) 2015-2017 Takashi Sakamoto
|
|
*
|
|
* Licensed under the terms of the GNU General Public License, version 2.
|
|
*/
|
|
|
|
#include "./ff.h"
|
|
|
|
static void proc_dump_clock_config(struct snd_info_entry *entry,
|
|
struct snd_info_buffer *buffer)
|
|
{
|
|
struct snd_ff *ff = entry->private_data;
|
|
__le32 reg;
|
|
u32 data;
|
|
unsigned int rate;
|
|
const char *src;
|
|
int err;
|
|
|
|
err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
|
|
SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0);
|
|
if (err < 0)
|
|
return;
|
|
|
|
data = le32_to_cpu(reg);
|
|
|
|
snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
|
|
(data & 0x20) ? "Professional" : "Consumer",
|
|
(data & 0x40) ? "on" : "off");
|
|
|
|
snd_iprintf(buffer, "Optical output interface format: %s\n",
|
|
((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
|
|
|
|
snd_iprintf(buffer, "Word output single speed: %s\n",
|
|
((data >> 8) & 0x20) ? "on" : "off");
|
|
|
|
snd_iprintf(buffer, "S/PDIF input interface: %s\n",
|
|
((data >> 8) & 0x02) ? "Optical" : "Coaxial");
|
|
|
|
switch ((data >> 1) & 0x03) {
|
|
case 0x01:
|
|
rate = 32000;
|
|
break;
|
|
case 0x00:
|
|
rate = 44100;
|
|
break;
|
|
case 0x03:
|
|
rate = 48000;
|
|
break;
|
|
case 0x02:
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (data & 0x08)
|
|
rate *= 2;
|
|
else if (data & 0x10)
|
|
rate *= 4;
|
|
|
|
snd_iprintf(buffer, "Sampling rate: %d\n", rate);
|
|
|
|
if (data & 0x01) {
|
|
src = "Internal";
|
|
} else {
|
|
switch ((data >> 10) & 0x07) {
|
|
case 0x00:
|
|
src = "ADAT1";
|
|
break;
|
|
case 0x01:
|
|
src = "ADAT2";
|
|
break;
|
|
case 0x03:
|
|
src = "S/PDIF";
|
|
break;
|
|
case 0x04:
|
|
src = "Word";
|
|
break;
|
|
case 0x05:
|
|
src = "LTC";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
snd_iprintf(buffer, "Sync to clock source: %s\n", src);
|
|
}
|
|
|
|
static void proc_dump_sync_status(struct snd_info_entry *entry,
|
|
struct snd_info_buffer *buffer)
|
|
{
|
|
struct snd_ff *ff = entry->private_data;
|
|
__le32 reg;
|
|
u32 data;
|
|
int err;
|
|
|
|
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
|
|
SND_FF_REG_SYNC_STATUS, ®, sizeof(reg), 0);
|
|
if (err < 0)
|
|
return;
|
|
|
|
data = le32_to_cpu(reg);
|
|
|
|
snd_iprintf(buffer, "External source detection:\n");
|
|
|
|
snd_iprintf(buffer, "Word Clock:");
|
|
if ((data >> 24) & 0x20) {
|
|
if ((data >> 24) & 0x40)
|
|
snd_iprintf(buffer, "sync\n");
|
|
else
|
|
snd_iprintf(buffer, "lock\n");
|
|
} else {
|
|
snd_iprintf(buffer, "none\n");
|
|
}
|
|
|
|
snd_iprintf(buffer, "S/PDIF:");
|
|
if ((data >> 16) & 0x10) {
|
|
if ((data >> 16) & 0x04)
|
|
snd_iprintf(buffer, "sync\n");
|
|
else
|
|
snd_iprintf(buffer, "lock\n");
|
|
} else {
|
|
snd_iprintf(buffer, "none\n");
|
|
}
|
|
|
|
snd_iprintf(buffer, "ADAT1:");
|
|
if ((data >> 8) & 0x04) {
|
|
if ((data >> 8) & 0x10)
|
|
snd_iprintf(buffer, "sync\n");
|
|
else
|
|
snd_iprintf(buffer, "lock\n");
|
|
} else {
|
|
snd_iprintf(buffer, "none\n");
|
|
}
|
|
|
|
snd_iprintf(buffer, "ADAT2:");
|
|
if ((data >> 8) & 0x08) {
|
|
if ((data >> 8) & 0x20)
|
|
snd_iprintf(buffer, "sync\n");
|
|
else
|
|
snd_iprintf(buffer, "lock\n");
|
|
} else {
|
|
snd_iprintf(buffer, "none\n");
|
|
}
|
|
|
|
snd_iprintf(buffer, "\nUsed external source:\n");
|
|
|
|
if (((data >> 22) & 0x07) == 0x07) {
|
|
snd_iprintf(buffer, "None\n");
|
|
} else {
|
|
switch ((data >> 22) & 0x07) {
|
|
case 0x00:
|
|
snd_iprintf(buffer, "ADAT1:");
|
|
break;
|
|
case 0x01:
|
|
snd_iprintf(buffer, "ADAT2:");
|
|
break;
|
|
case 0x03:
|
|
snd_iprintf(buffer, "S/PDIF:");
|
|
break;
|
|
case 0x04:
|
|
snd_iprintf(buffer, "Word:");
|
|
break;
|
|
case 0x07:
|
|
snd_iprintf(buffer, "Nothing:");
|
|
break;
|
|
case 0x02:
|
|
case 0x05:
|
|
case 0x06:
|
|
default:
|
|
snd_iprintf(buffer, "unknown:");
|
|
break;
|
|
}
|
|
|
|
if ((data >> 25) & 0x07) {
|
|
switch ((data >> 25) & 0x07) {
|
|
case 0x01:
|
|
snd_iprintf(buffer, "32000\n");
|
|
break;
|
|
case 0x02:
|
|
snd_iprintf(buffer, "44100\n");
|
|
break;
|
|
case 0x03:
|
|
snd_iprintf(buffer, "48000\n");
|
|
break;
|
|
case 0x04:
|
|
snd_iprintf(buffer, "64000\n");
|
|
break;
|
|
case 0x05:
|
|
snd_iprintf(buffer, "88200\n");
|
|
break;
|
|
case 0x06:
|
|
snd_iprintf(buffer, "96000\n");
|
|
break;
|
|
case 0x07:
|
|
snd_iprintf(buffer, "128000\n");
|
|
break;
|
|
case 0x08:
|
|
snd_iprintf(buffer, "176400\n");
|
|
break;
|
|
case 0x09:
|
|
snd_iprintf(buffer, "192000\n");
|
|
break;
|
|
case 0x00:
|
|
snd_iprintf(buffer, "unknown\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
snd_iprintf(buffer, "Multiplied:");
|
|
snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
|
|
}
|
|
|
|
static void add_node(struct snd_ff *ff, struct snd_info_entry *root,
|
|
const char *name,
|
|
void (*op)(struct snd_info_entry *e,
|
|
struct snd_info_buffer *b))
|
|
{
|
|
struct snd_info_entry *entry;
|
|
|
|
entry = snd_info_create_card_entry(ff->card, name, root);
|
|
if (entry == NULL)
|
|
return;
|
|
|
|
snd_info_set_text_ops(entry, ff, op);
|
|
if (snd_info_register(entry) < 0)
|
|
snd_info_free_entry(entry);
|
|
}
|
|
|
|
void snd_ff_proc_init(struct snd_ff *ff)
|
|
{
|
|
struct snd_info_entry *root;
|
|
|
|
/*
|
|
* All nodes are automatically removed at snd_card_disconnect(),
|
|
* by following to link list.
|
|
*/
|
|
root = snd_info_create_card_entry(ff->card, "firewire",
|
|
ff->card->proc_root);
|
|
if (root == NULL)
|
|
return;
|
|
root->mode = S_IFDIR | 0555;
|
|
if (snd_info_register(root) < 0) {
|
|
snd_info_free_entry(root);
|
|
return;
|
|
}
|
|
|
|
add_node(ff, root, "clock-config", proc_dump_clock_config);
|
|
add_node(ff, root, "sync-status", proc_dump_sync_status);
|
|
}
|