--- /dev/null
+/*
+ * oxfw_stream.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ err = cmp_connection_init(&oxfw->in_conn, oxfw->unit,
+ CMP_INPUT, 0);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_init(&oxfw->rx_stream, oxfw->unit,
+ AMDTP_OUT_STREAM, CIP_NONBLOCKING);
+ if (err < 0) {
+ amdtp_stream_destroy(&oxfw->rx_stream);
+ cmp_connection_destroy(&oxfw->in_conn);
+ }
+end:
+ return err;
+}
+
+static void stop_stream(struct snd_oxfw *oxfw)
+{
+ amdtp_stream_pcm_abort(&oxfw->rx_stream);
+ amdtp_stream_stop(&oxfw->rx_stream);
+ cmp_connection_break(&oxfw->in_conn);
+}
+
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw)
+{
+ int err = 0;
+
+ if (amdtp_streaming_error(&oxfw->rx_stream))
+ stop_stream(oxfw);
+
+ if (amdtp_stream_running(&oxfw->rx_stream))
+ goto end;
+
+ err = cmp_connection_establish(&oxfw->in_conn,
+ amdtp_stream_get_max_payload(&oxfw->rx_stream));
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_start(&oxfw->rx_stream,
+ oxfw->in_conn.resources.channel,
+ oxfw->in_conn.speed);
+ if (err < 0)
+ stop_stream(oxfw);
+end:
+ return err;
+}
+
+void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw)
+{
+ stop_stream(oxfw);
+}
+
+void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw)
+{
+ stop_stream(oxfw);
+
+ amdtp_stream_destroy(&oxfw->rx_stream);
+ cmp_connection_destroy(&oxfw->in_conn);
+}
+
+void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw)
+{
+ if (cmp_connection_update(&oxfw->in_conn) < 0)
+ stop_stream(oxfw);
+ else
+ amdtp_stream_update(&oxfw->rx_stream);
+}
* Licensed under the terms of the GNU General Public License, version 2.
*/
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include "../cmp.h"
-#include "../fcp.h"
-#include "../amdtp.h"
-#include "../lib.h"
+#include "oxfw.h"
#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
#define SPECIFIER_1394TA 0x00a02d
#define VERSION_AVC 0x010001
-struct device_info {
- const char *driver_name;
- const char *short_name;
- const char *long_name;
- int (*pcm_constraints)(struct snd_pcm_runtime *runtime);
- unsigned int mixer_channels;
- u8 mute_fb_id;
- u8 volume_fb_id;
-};
-
-struct snd_oxfw {
- struct snd_card *card;
- struct fw_unit *unit;
- const struct device_info *device_info;
- struct mutex mutex;
- struct cmp_connection in_conn;
- struct amdtp_stream rx_stream;
- bool mute;
- s16 volume[6];
- s16 volume_min;
- s16 volume_max;
-};
-
MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");
return 0;
}
-static void oxfw_stop_stream(struct snd_oxfw *oxfw)
-{
- if (amdtp_stream_running(&oxfw->rx_stream)) {
- amdtp_stream_stop(&oxfw->rx_stream);
- cmp_connection_break(&oxfw->in_conn);
- }
-}
-
static int oxfw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int err;
mutex_lock(&oxfw->mutex);
- oxfw_stop_stream(oxfw);
- mutex_unlock(&oxfw->mutex);
+
+ snd_oxfw_stream_stop_simplex(oxfw);
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
err_buffer:
snd_pcm_lib_free_vmalloc_buffer(substream);
error:
+ mutex_unlock(&oxfw->mutex);
return err;
}
struct snd_oxfw *oxfw = substream->private_data;
mutex_lock(&oxfw->mutex);
- oxfw_stop_stream(oxfw);
+ snd_oxfw_stream_stop_simplex(oxfw);
mutex_unlock(&oxfw->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
mutex_lock(&oxfw->mutex);
- if (amdtp_streaming_error(&oxfw->rx_stream))
- oxfw_stop_stream(oxfw);
-
- if (!amdtp_stream_running(&oxfw->rx_stream)) {
- err = cmp_connection_establish(&oxfw->in_conn,
- amdtp_stream_get_max_payload(&oxfw->rx_stream));
- if (err < 0)
- goto err_mutex;
+ snd_oxfw_stream_stop_simplex(oxfw);
- err = amdtp_stream_start(&oxfw->rx_stream,
- oxfw->in_conn.resources.channel,
- oxfw->in_conn.speed);
- if (err < 0)
- goto err_connection;
- }
-
- mutex_unlock(&oxfw->mutex);
+ err = snd_oxfw_stream_start_simplex(oxfw);
+ if (err < 0)
+ goto end;
amdtp_stream_pcm_prepare(&oxfw->rx_stream);
-
- return 0;
-
-err_connection:
- cmp_connection_break(&oxfw->in_conn);
-err_mutex:
+end:
mutex_unlock(&oxfw->mutex);
-
return err;
}
{
struct snd_oxfw *oxfw = card->private_data;
- amdtp_stream_destroy(&oxfw->rx_stream);
- cmp_connection_destroy(&oxfw->in_conn);
- fw_unit_put(oxfw->unit);
mutex_destroy(&oxfw->mutex);
}
if (err < 0)
return err;
+ card->private_free = oxfw_card_free;
oxfw = card->private_data;
oxfw->card = card;
mutex_init(&oxfw->mutex);
- oxfw->unit = fw_unit_get(unit);
+ oxfw->unit = unit;
oxfw->device_info = (const struct device_info *)id->driver_data;
- err = cmp_connection_init(&oxfw->in_conn, unit, CMP_INPUT, 0);
- if (err < 0)
- goto err_unit;
-
- err = amdtp_stream_init(&oxfw->rx_stream, unit, AMDTP_OUT_STREAM,
- CIP_NONBLOCKING);
- if (err < 0)
- goto err_connection;
-
- card->private_free = oxfw_card_free;
-
strcpy(card->driver, oxfw->device_info->driver_name);
strcpy(card->shortname, oxfw->device_info->short_name);
firmware = oxfw_read_firmware_version(unit);
if (err < 0)
goto error;
- err = snd_card_register(card);
+ err = snd_oxfw_stream_init_simplex(oxfw);
if (err < 0)
goto error;
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_oxfw_stream_destroy_simplex(oxfw);
+ goto error;
+ }
dev_set_drvdata(&unit->device, oxfw);
return 0;
-
-err_connection:
- cmp_connection_destroy(&oxfw->in_conn);
-err_unit:
- fw_unit_put(oxfw->unit);
- mutex_destroy(&oxfw->mutex);
error:
snd_card_free(card);
return err;
fcp_bus_reset(oxfw->unit);
- if (cmp_connection_update(&oxfw->in_conn) < 0) {
- amdtp_stream_pcm_abort(&oxfw->rx_stream);
- mutex_lock(&oxfw->mutex);
- oxfw_stop_stream(oxfw);
- mutex_unlock(&oxfw->mutex);
- return;
- }
-
- amdtp_stream_update(&oxfw->rx_stream);
+ mutex_lock(&oxfw->mutex);
+ snd_oxfw_stream_update_simplex(oxfw);
+ mutex_unlock(&oxfw->mutex);
}
static void oxfw_remove(struct fw_unit *unit)
{
struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
- amdtp_stream_pcm_abort(&oxfw->rx_stream);
snd_card_disconnect(oxfw->card);
- mutex_lock(&oxfw->mutex);
- oxfw_stop_stream(oxfw);
- mutex_unlock(&oxfw->mutex);
+ snd_oxfw_stream_destroy_simplex(oxfw);
snd_card_free_when_closed(oxfw->card);
}
--- /dev/null
+/*
+ * oxfw.h - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "../lib.h"
+#include "../fcp.h"
+#include "../packets-buffer.h"
+#include "../iso-resources.h"
+#include "../amdtp.h"
+#include "../cmp.h"
+
+struct device_info {
+ const char *driver_name;
+ const char *short_name;
+ const char *long_name;
+ int (*pcm_constraints)(struct snd_pcm_runtime *runtime);
+ unsigned int mixer_channels;
+ u8 mute_fb_id;
+ u8 volume_fb_id;
+};
+
+struct snd_oxfw {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ const struct device_info *device_info;
+ struct mutex mutex;
+ struct cmp_connection in_conn;
+ struct amdtp_stream rx_stream;
+ bool mute;
+ s16 volume[6];
+ s16 volume_min;
+ s16 volume_max;
+};
+
+int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw);
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw);