/*
* TC Applied Technologies Digital Interface Communications Engine driver
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
* Licensed under the terms of the GNU General Public License, version 2.
*/
#include <linux/compat.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/firewire.h>
#include <sound/hwdep.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "amdtp.h"
#include "iso-resources.h"
#include "lib.h"
#include "dice-interface.h"
struct dice {
struct snd_card *card;
struct fw_unit *unit;
spinlock_t lock;
struct mutex mutex;
unsigned int global_offset;
unsigned int rx_offset;
unsigned int clock_caps;
unsigned int rx_channels[3];
unsigned int rx_midi_ports[3];
struct fw_address_handler notification_handler;
int owner_generation;
int dev_lock_count; /* > 0 driver, < 0 userspace */
bool dev_lock_changed;
bool global_enabled;
struct completion clock_accepted;
wait_queue_head_t hwdep_wait;
u32 notification_bits;
struct fw_iso_resources resources;
struct amdtp_out_stream stream;
};
MODULE_DESCRIPTION("DICE driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");
static const unsigned int dice_rates[] = {
/* mode 0 */
[0] = 32000,
[1] = 44100,
[2] = 48000,
/* mode 1 */
[3] = 88200,
[4] = 96000,
/* mode 2 */
[5] = 176400,
[6] = 192000,
};
static unsigned int rate_to_index(unsigned int rate)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
if (dice_rates[i] == rate)
return i;
return 0;
}
static unsigned int rate_index_to_mode(unsigned int rate_index)
{
return ((int)rate_index - 1) / 2;
}
static void dice_lock_changed(struct dice *dice)
{
dice->dev_lock_changed = true;
wake_up(&dice->hwdep_wait);
}
static int dice_try_lock(struct dice *dice)
{
int err;
spin_lock_irq(&dice->lock);
if (dice->dev_lock_count < 0) {
err = -EBUSY;
goto out;
}
if (dice->dev_lock_count++ == 0)