blob: 9bd30c6bc93f8190c8110447119cb86c2646c3da [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <string.h>
#include <errno.h>
#include "internal.h"
#include "snd_tscm.h"
#include "hinawa_sigs_marshal.h"
/**
* SECTION:snd_tscm
* @Title: HinawaSndTscm
* @Short_description: A state reader for Tascam FireWire models
* @include: snd_tscm.h
*
* A #HinawaSndTscm is an application of protocol defined by TASCAM. This
* inherits #HinawaSndUnit.
*/
struct _HinawaSndTscmPrivate {
struct snd_firewire_tascam_state image;
guint32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
};
G_DEFINE_TYPE_WITH_PRIVATE(HinawaSndTscm, hinawa_snd_tscm, HINAWA_TYPE_SND_UNIT)
/* This object has one signal. */
enum tscm_sig_type {
TSCM_SIG_TYPE_CTL,
TSCM_SIG_TYPE_COUNT,
};
static guint tscm_sigs[TSCM_SIG_TYPE_COUNT] = { 0 };
static void hinawa_snd_tscm_class_init(HinawaSndTscmClass *klass)
{
/**
* HinawaSndTscm::control:
* @self: A #HinawaSndTscm
* @index: the numerical index on image of status and control info.
* @before: the value of info before changed.
* @after: the value of info after changed.
*
* When TASCAM FireWire unit transfer control message, the #HinawaSndTscm::control
* signal is emitted.
*/
tscm_sigs[TSCM_SIG_TYPE_CTL] =
g_signal_new("control",
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(HinawaSndTscmClass, control),
NULL, NULL,
hinawa_sigs_marshal_VOID__UINT_UINT_UINT,
G_TYPE_NONE,
3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
}
static void hinawa_snd_tscm_init(HinawaSndTscm *self)
{
return;
}
/**
* hinawa_snd_tscm_new:
*
* Instantiate #HinawaSndTscm object and return the instance.
*
* Returns: an instance of #HinawaSndTscm.
* Since: 1.3.
*/
HinawaSndTscm *hinawa_snd_tscm_new(void)
{
return g_object_new(HINAWA_TYPE_SND_TSCM, NULL);
}
/**
* hinawa_snd_tscm_open:
* @self: A #HinawaSndUnit
* @path: A full path of a special file for ALSA hwdep character device
* @exception: A #GError. Error can be generated with three domains; #g_file_error_quark(),
* #hinawa_fw_node_error_quark(), and #hinawa_snd_unit_error_quark().
*
* Open ALSA hwdep character device and check it for Dg00x devices.
*/
void hinawa_snd_tscm_open(HinawaSndTscm *self, gchar *path, GError **exception)
{
g_return_if_fail(HINAWA_IS_SND_TSCM(self));
g_return_if_fail(path != NULL && strlen(path) > 0);
g_return_if_fail(exception == NULL || *exception == NULL);
hinawa_snd_unit_open(&self->parent_instance, path, exception);
}
/**
* hinawa_snd_tscm_get_state:
* @self: A #HinawaSndTscm
* @exception: A #GError. Error can be generated with domain of #hinawa_snd_unit_error_quark().
*
* Get the latest states of target device.
*
* Returns: (element-type guint32) (array fixed-size=64) (transfer none): state
* image.
*
*/
const guint32 *hinawa_snd_tscm_get_state(HinawaSndTscm *self,
GError **exception)
{
HinawaSndTscmPrivate *priv;
int i;
g_return_val_if_fail(HINAWA_IS_SND_TSCM(self), NULL);
g_return_val_if_fail(exception == NULL || *exception == NULL, NULL);
priv = hinawa_snd_tscm_get_instance_private(self);
hinawa_snd_unit_ioctl(&self->parent_instance,
SNDRV_FIREWIRE_IOCTL_TASCAM_STATE, &priv->image,
exception);
if (*exception != NULL)
return NULL;
for (i = 0; i < SNDRV_FIREWIRE_TASCAM_STATE_COUNT; ++i)
priv->state[i] = GUINT32_FROM_BE(priv->image.data[i]);
return priv->state;
}
void hinawa_snd_tscm_handle_control(HinawaSndTscm *self, const void *buf,
ssize_t len)
{
const struct snd_firewire_event_tascam_control *event =
(struct snd_firewire_event_tascam_control *)buf;
const struct snd_firewire_tascam_change *change;
g_return_if_fail(HINAWA_IS_SND_TSCM(self));
if (len < sizeof(event->type))
return;
len -= sizeof(event->type);
change = event->changes;
while (len >= sizeof(*change)) {
g_signal_emit(self, tscm_sigs[TSCM_SIG_TYPE_CTL], 0,
change->index,
GUINT32_FROM_BE(change->before),
GUINT32_FROM_BE(change->after));
++change;
len -= sizeof(*change);
}
}