Merge branch 'for-next' into for-linus

This commit is contained in:
Takashi Iwai 2021-07-01 08:34:15 +02:00
commit 498386d1c4
306 changed files with 10617 additions and 6174 deletions

View File

@ -75,6 +75,10 @@ properties:
$ref: "/schemas/types.yaml#/definitions/uint32"
enum: [ 0, 1, 2, 3 ]
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg

View File

@ -102,7 +102,7 @@ Conexant codecs
---------------
Auto-Mute Mode
See Reatek codecs.
See Realtek codecs.
Analog codecs

View File

@ -7112,6 +7112,13 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/joystick/fsia6b.c
FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER
M: Geoffrey D. Bennett <g@b4.vu>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
F: sound/usb/mixer_scarlett_gen2.c
FORCEDETH GIGABIT ETHERNET DRIVER
M: Rain River <rain.1986.08.12@gmail.com>
M: Zhu Yanjun <zyjzyj2000@gmail.com>

View File

@ -492,7 +492,7 @@ int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
}
EXPORT_SYMBOL(sdw_read_no_pm);
static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
@ -503,6 +503,21 @@ static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
tmp = (tmp & ~mask) | val;
return sdw_write_no_pm(slave, addr, tmp);
}
EXPORT_SYMBOL(sdw_update_no_pm);
/* Read-Modify-Write Slave register */
int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
tmp = sdw_read(slave, addr);
if (tmp < 0)
return tmp;
tmp = (tmp & ~mask) | val;
return sdw_write(slave, addr, tmp);
}
EXPORT_SYMBOL(sdw_update);
/**
* sdw_nread() - Read "n" contiguous SDW Slave registers

View File

@ -201,19 +201,6 @@ static inline void sdw_fill_port_params(struct sdw_port_params *params,
params->data_mode = data_mode;
}
/* Read-Modify-Write Slave register */
static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
tmp = sdw_read(slave, addr);
if (tmp < 0)
return tmp;
tmp = (tmp & ~mask) | val;
return sdw_write(slave, addr, tmp);
}
/* broadcast read/write for tests */
int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr);
int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value);

View File

@ -1041,6 +1041,9 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value);
int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);

View File

@ -128,7 +128,9 @@ struct snd_card {
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
atomic_t power_ref;
wait_queue_head_t power_sleep;
wait_queue_head_t power_ref_sleep;
#endif
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
@ -142,21 +144,61 @@ struct snd_card {
#ifdef CONFIG_PM
static inline unsigned int snd_power_get_state(struct snd_card *card)
{
return card->power_state;
return READ_ONCE(card->power_state);
}
static inline void snd_power_change_state(struct snd_card *card, unsigned int state)
{
card->power_state = state;
WRITE_ONCE(card->power_state, state);
wake_up(&card->power_sleep);
}
/**
* snd_power_ref - Take the reference count for power control
* @card: sound card object
*
* The power_ref reference of the card is used for managing to block
* the snd_power_sync_ref() operation. This function increments the reference.
* The counterpart snd_power_unref() has to be called appropriately later.
*/
static inline void snd_power_ref(struct snd_card *card)
{
atomic_inc(&card->power_ref);
}
/**
* snd_power_unref - Release the reference count for power control
* @card: sound card object
*/
static inline void snd_power_unref(struct snd_card *card)
{
if (atomic_dec_and_test(&card->power_ref))
wake_up(&card->power_ref_sleep);
}
/**
* snd_power_sync_ref - wait until the card power_ref is freed
* @card: sound card object
*
* This function is used to synchronize with the pending power_ref being
* released.
*/
static inline void snd_power_sync_ref(struct snd_card *card)
{
wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref));
}
/* init.c */
int snd_power_wait(struct snd_card *card, unsigned int power_state);
int snd_power_wait(struct snd_card *card);
int snd_power_ref_and_wait(struct snd_card *card);
#else /* ! CONFIG_PM */
static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
static inline int snd_power_wait(struct snd_card *card) { return 0; }
static inline void snd_power_ref(struct snd_card *card) {}
static inline void snd_power_unref(struct snd_card *card) {}
static inline int snd_power_ref_and_wait(struct snd_card *card) { return 0; }
static inline void snd_power_sync_ref(struct snd_card *card) {}
#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; })
#define snd_power_change_state(card, state) do { (void)(card); } while (0)

View File

@ -12,6 +12,7 @@
#include <asm/page.h>
struct device;
struct vm_area_struct;
/*
* buffer device info
@ -64,84 +65,19 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
#ifdef CONFIG_SND_DMA_SGBUF
/*
* Scatter-Gather generic device pages
*/
void *snd_malloc_sgbuf_pages(struct device *device,
size_t size, struct snd_dma_buffer *dmab,
size_t *res_size);
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table; /* address table */
struct page **page_table; /* page table (for vmap/vunmap) */
struct device *dev;
};
/*
* return the physical address at the corresponding offset
*/
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
dma_addr_t addr;
if (!sgbuf)
return dmab->addr + offset;
addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
addr &= ~((dma_addr_t)PAGE_SIZE - 1);
return addr + offset % PAGE_SIZE;
}
/*
* return the virtual address at the corresponding offset
*/
static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
if (!sgbuf)
return dmab->area + offset;
return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
}
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
#else
/* non-SG versions */
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
return dmab->addr + offset;
}
static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
size_t offset)
{
return dmab->area + offset;
}
#define snd_sgbuf_get_chunk_size(dmab, ofs, size) (size)
#endif /* CONFIG_SND_DMA_SGBUF */
/* allocate/release a buffer */
int snd_dma_alloc_pages(int type, struct device *dev, size_t size,
struct snd_dma_buffer *dmab);
int snd_dma_alloc_pages_fallback(int type, struct device *dev, size_t size,
struct snd_dma_buffer *dmab);
void snd_dma_free_pages(struct snd_dma_buffer *dmab);
int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area);
dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset);
struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset);
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
#endif /* __SOUND_MEMALLOC_H */

View File

@ -1066,6 +1066,7 @@ void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
void snd_pcm_set_sync(struct snd_pcm_substream *substream);
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream);
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
void *buf, bool interleaved,
@ -1253,14 +1254,6 @@ static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
#ifdef CONFIG_SND_DMA_SGBUF
/*
* SG-buffer handling
*/
#define snd_pcm_substream_sgbuf(substream) \
snd_pcm_get_dma_buf(substream)->private_data
#endif /* SND_DMA_SGBUF */
/**
* snd_pcm_sgbuf_get_addr - Get the DMA address at the corresponding offset
* @substream: PCM substream
@ -1272,17 +1265,6 @@ snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs);
}
/**
* snd_pcm_sgbuf_get_ptr - Get the virtual address at the corresponding offset
* @substream: PCM substream
* @ofs: byte offset
*/
static inline void *
snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
{
return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);
}
/**
* snd_pcm_sgbuf_get_chunk_size - Compute the max size that fits within the
* contig. page from the given size

View File

@ -81,6 +81,8 @@ struct snd_rawmidi_substream {
bool opened; /* open flag */
bool append; /* append flag (merge more streams) */
bool active_sensing; /* send active sensing when close */
unsigned int framing; /* whether to frame input data */
unsigned int clock_type; /* clock source to use for input framing */
int use_count; /* use counter (for output) */
size_t bytes;
struct snd_rawmidi *rmidi;

View File

@ -710,7 +710,7 @@ enum {
* Raw MIDI section - /dev/snd/midi??
*/
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1)
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2)
enum {
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
@ -736,12 +736,38 @@ struct snd_rawmidi_info {
unsigned char reserved[64]; /* reserved for future use */
};
#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0)
#define SNDRV_RAWMIDI_MODE_FRAMING_SHIFT 0
#define SNDRV_RAWMIDI_MODE_FRAMING_NONE (0<<0)
#define SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP (1<<0)
#define SNDRV_RAWMIDI_MODE_CLOCK_MASK (7<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_SHIFT 3
#define SNDRV_RAWMIDI_MODE_CLOCK_NONE (0<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_REALTIME (1<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC (2<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW (3<<3)
#define SNDRV_RAWMIDI_FRAMING_DATA_LENGTH 16
struct snd_rawmidi_framing_tstamp {
/* For now, frame_type is always 0. Midi 2.0 is expected to add new
* types here. Applications are expected to skip unknown frame types.
*/
__u8 frame_type;
__u8 length; /* number of valid bytes in data field */
__u8 reserved[2];
__u32 tv_nsec; /* nanoseconds */
__u64 tv_sec; /* seconds */
__u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH];
} __packed;
struct snd_rawmidi_params {
int stream;
size_t buffer_size; /* queue size in bytes */
size_t avail_min; /* minimum avail bytes for wakeup */
unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */
unsigned char reserved[16]; /* reserved for future use */
unsigned int mode; /* For input data only, frame incoming data */
unsigned char reserved[12]; /* reserved for future use */
};
#ifndef __KERNEL__

View File

@ -520,7 +520,7 @@ static int ac97_bus_remove(struct device *dev)
struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
int ret;
ret = pm_runtime_get_sync(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;

View File

@ -918,10 +918,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
}
cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL);
if (!cii) {
printk(KERN_DEBUG "i2sbus: failed to allocate cii\n");
if (!cii)
return -ENOMEM;
}
/* use the private data to point to the codec info */
cii->sdev = soundbus_dev_get(dev);

View File

@ -47,9 +47,7 @@ static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
unsigned short reg, unsigned short val)
{
int __always_unused ret;
ret = pxa2xx_ac97_write(ac97->num, reg, val);
pxa2xx_ac97_write(ac97->num, reg, val);
}
static const struct snd_ac97_bus_ops pxa2xx_ac97_ops = {

View File

@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card,
#ifdef CONFIG_SND_DEBUG
info->access = 0;
#endif
result = kctl->info(kctl, info);
result = snd_power_ref_and_wait(card);
if (!result)
result = kctl->info(kctl, info);
snd_power_unref(card);
if (result >= 0) {
snd_BUG_ON(info->access);
index_offset = snd_ctl_get_ioff(kctl, &info->id);
@ -1042,9 +1045,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
if (result < 0)
return result;
result = snd_ctl_elem_info(ctl, &info);
if (result < 0)
return result;
@ -1088,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card,
if (!snd_ctl_skip_validation(&info))
fill_remaining_elem_value(control, &info, pattern);
ret = kctl->get(kctl, control);
ret = snd_power_ref_and_wait(card);
if (!ret)
ret = kctl->get(kctl, control);
snd_power_unref(card);
if (ret < 0)
return ret;
if (!snd_ctl_skip_validation(&info) &&
@ -1113,10 +1116,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
if (IS_ERR(control))
return PTR_ERR(control);
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto error;
down_read(&card->controls_rwsem);
result = snd_ctl_elem_read(card, control);
up_read(&card->controls_rwsem);
@ -1154,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
}
snd_ctl_build_ioff(&control->id, kctl, index_offset);
result = kctl->put(kctl, control);
result = snd_power_ref_and_wait(card);
if (!result)
result = kctl->put(kctl, control);
snd_power_unref(card);
if (result < 0) {
up_write(&card->controls_rwsem);
return result;
@ -1183,10 +1185,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
return PTR_ERR(control);
card = file->card;
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto error;
result = snd_ctl_elem_write(card, file, control);
if (result < 0)
goto error;
@ -1669,7 +1667,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
{SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
};
struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
int i;
int i, ret;
/* Check support of the request for this element. */
for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
@ -1687,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
vd->owner != NULL && vd->owner != file)
return -EPERM;
return kctl->tlv.c(kctl, op_flag, size, buf);
ret = snd_power_ref_and_wait(file->card);
if (!ret)
ret = kctl->tlv.c(kctl, op_flag, size, buf);
snd_power_unref(file->card);
return ret;
}
static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
@ -1815,11 +1817,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
#ifdef CONFIG_PM
return put_user(card->power_state, ip) ? -EFAULT : 0;
#else
return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
#endif
}
down_read(&snd_ioctl_rwsem);
list_for_each_entry(p, &snd_control_ioctls, list) {

View File

@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
goto error;
err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
if (err < 0)
goto error;
err = snd_ctl_elem_info(ctl, data);
if (err < 0)
goto error;
@ -187,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
return -ENOMEM;
}
info->id = *id;
err = kctl->info(kctl, info);
err = snd_power_ref_and_wait(card);
if (!err)
err = kctl->info(kctl, info);
snd_power_unref(card);
up_read(&card->controls_rwsem);
if (err >= 0) {
err = info->type;
@ -298,9 +298,6 @@ static int ctl_elem_read_user(struct snd_card *card,
if (err < 0)
goto error;
err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (err < 0)
goto error;
err = snd_ctl_elem_read(card, data);
if (err < 0)
goto error;
@ -326,9 +323,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
if (err < 0)
goto error;
err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (err < 0)
goto error;
err = snd_ctl_elem_write(card, file, data);
if (err < 0)
goto error;

View File

@ -393,11 +393,11 @@ static void snd_ctl_led_dev_release(struct device *dev)
* sysfs
*/
static ssize_t show_mode(struct device *dev,
static ssize_t mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
const char *str;
const char *str = NULL;
switch (led->mode) {
case MODE_FOLLOW_MUTE: str = "follow-mute"; break;
@ -408,7 +408,8 @@ static ssize_t show_mode(struct device *dev,
return sprintf(buf, "%s\n", str);
}
static ssize_t store_mode(struct device *dev, struct device_attribute *attr,
static ssize_t mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
@ -437,7 +438,7 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *attr,
return count;
}
static ssize_t show_brightness(struct device *dev,
static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
@ -445,8 +446,8 @@ static ssize_t show_brightness(struct device *dev,
return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
}
static DEVICE_ATTR(mode, 0644, show_mode, store_mode);
static DEVICE_ATTR(brightness, 0444, show_brightness, NULL);
static DEVICE_ATTR_RW(mode);
static DEVICE_ATTR_RO(brightness);
static struct attribute *snd_ctl_led_dev_attrs[] = {
&dev_attr_mode.attr,
@ -580,22 +581,25 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si
return count;
}
static ssize_t parse_attach(struct device *dev, struct device_attribute *attr,
static ssize_t attach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
return set_led_id(led_card, buf, count, true);
}
static ssize_t parse_detach(struct device *dev, struct device_attribute *attr,
static ssize_t detach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
return set_led_id(led_card, buf, count, false);
}
static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t reset_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
int err;
@ -608,8 +612,8 @@ static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr,
return count;
}
static ssize_t ctl_list(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t list_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
struct snd_card *card;
@ -642,10 +646,10 @@ static ssize_t ctl_list(struct device *dev,
return buf2 - buf;
}
static DEVICE_ATTR(attach, 0200, NULL, parse_attach);
static DEVICE_ATTR(detach, 0200, NULL, parse_detach);
static DEVICE_ATTR(reset, 0200, NULL, ctl_reset);
static DEVICE_ATTR(list, 0444, ctl_list, NULL);
static DEVICE_ATTR_WO(attach);
static DEVICE_ATTR_WO(detach);
static DEVICE_ATTR_WO(reset);
static DEVICE_ATTR_RO(list);
static struct attribute *snd_ctl_led_card_attrs[] = {
&dev_attr_attach.attr,

View File

@ -195,7 +195,8 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw,
return -ENXIO;
memset(&info, 0, sizeof(info));
info.dsp_loaded = hw->dsp_loaded;
if ((err = hw->ops.dsp_status(hw, &info)) < 0)
err = hw->ops.dsp_status(hw, &info);
if (err < 0)
return err;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@ -500,7 +501,8 @@ static void __init snd_hwdep_proc_init(void)
{
struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) {
entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL);
if (entry) {
entry->c.text.read = snd_hwdep_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);

View File

@ -31,7 +31,8 @@ int snd_oss_info_register(int dev, int num, char *string)
return -ENXIO;
mutex_lock(&strings);
if (string == NULL) {
if ((x = snd_sndstat_strings[num][dev]) != NULL) {
x = snd_sndstat_strings[num][dev];
if (x) {
kfree(x);
x = NULL;
}

View File

@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
mutex_init(&card->memory_mutex);
#ifdef CONFIG_PM
init_waitqueue_head(&card->power_sleep);
init_waitqueue_head(&card->power_ref_sleep);
atomic_set(&card->power_ref, 0);
#endif
init_waitqueue_head(&card->remove_sleep);
card->sync_irq = -1;
@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
snd_power_sync_ref(card);
#endif
return 0;
}
@ -662,17 +665,15 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
}
EXPORT_SYMBOL(snd_card_set_id);
static ssize_t
card_id_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
return scnprintf(buf, PAGE_SIZE, "%s\n", card->id);
}
static ssize_t
card_id_store_attr(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t id_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
char buf1[sizeof(card->id)];
@ -700,17 +701,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(id, 0644, card_id_show_attr, card_id_store_attr);
static DEVICE_ATTR_RW(id);
static ssize_t
card_number_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
return scnprintf(buf, PAGE_SIZE, "%i\n", card->number);
}
static DEVICE_ATTR(number, 0444, card_number_show_attr, NULL);
static DEVICE_ATTR_RO(number);
static struct attribute *card_dev_attrs[] = {
&dev_attr_id.attr,
@ -770,7 +770,8 @@ int snd_card_register(struct snd_card *card)
card->registered = true;
}
if ((err = snd_device_register_all(card)) < 0)
err = snd_device_register_all(card);
if (err < 0)
return err;
mutex_lock(&snd_card_mutex);
if (snd_cards[card->number]) {
@ -813,7 +814,8 @@ static void snd_card_info_read(struct snd_info_entry *entry,
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n",
idx,
@ -837,7 +839,8 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
@ -859,7 +862,8 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
for (idx = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL)
card = snd_cards[idx];
if (card)
snd_iprintf(buffer, "%2i %s\n",
idx, card->module->name);
mutex_unlock(&snd_card_mutex);
@ -1002,21 +1006,28 @@ EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_PM
/**
* snd_power_wait - wait until the power-state is changed.
* @card: soundcard structure
* @power_state: expected power state
* snd_power_ref_and_wait - wait until the card gets powered up
* @card: soundcard structure
*
* Waits until the power-state is changed.
* Take the power_ref reference count of the given card, and
* wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
* The refcount is down again while sleeping until power-up, hence this
* function can be used for syncing the floating control ops accesses,
* typically around calling control ops.
*
* Return: Zero if successful, or a negative error code.
* The caller needs to pull down the refcount via snd_power_unref() later
* no matter whether the error is returned from this function or not.
*
* Return: Zero if successful, or a negative error code.
*/
int snd_power_wait(struct snd_card *card, unsigned int power_state)
int snd_power_ref_and_wait(struct snd_card *card)
{
wait_queue_entry_t wait;
int result = 0;
snd_power_ref(card);
/* fastpath */
if (snd_power_get_state(card) == power_state)
if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0)
return 0;
init_waitqueue_entry(&wait, current);
add_wait_queue(&card->power_sleep, &wait);
@ -1025,13 +1036,33 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
result = -ENODEV;
break;
}
if (snd_power_get_state(card) == power_state)
if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0)
break;
snd_power_unref(card);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(30 * HZ);
snd_power_ref(card);
}
remove_wait_queue(&card->power_sleep, &wait);
return result;
}
EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);
/**
* snd_power_wait - wait until the card gets powered up (old form)
* @card: soundcard structure
*
* Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
*
* Return: Zero if successful, or a negative error code.
*/
int snd_power_wait(struct snd_card *card)
{
int ret;
ret = snd_power_ref_and_wait(card);
snd_power_unref(card);
return ret;
}
EXPORT_SYMBOL(snd_power_wait);
#endif /* CONFIG_PM */

View File

@ -15,99 +15,27 @@
#include <asm/set_memory.h>
#endif
#include <sound/memalloc.h>
#include "memalloc_local.h"
/*
*
* Bus-specific memory allocators
*
*/
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab);
#ifdef CONFIG_HAS_DMA
/* allocate the coherent DMA pages */
static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp_flags;
gfp_flags = GFP_KERNEL
| __GFP_COMP /* compound page lets parts be mapped */
| __GFP_NORETRY /* don't trigger OOM-killer */
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
gfp_flags);
#ifdef CONFIG_X86
if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wc((unsigned long)dmab->area,
PAGE_ALIGN(size) >> PAGE_SHIFT);
#endif
}
/* free the coherent DMA pages */
static void snd_free_dev_pages(struct snd_dma_buffer *dmab)
{
#ifdef CONFIG_X86
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wb((unsigned long)dmab->area,
PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
#endif
dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
}
#ifdef CONFIG_GENERIC_ALLOCATOR
/**
* snd_malloc_dev_iram - allocate memory from on-chip internal ram
* @dmab: buffer allocation record to store the allocated data
* @size: number of bytes to allocate from the iram
*
* This function requires iram phandle provided via of_node
*/
static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size)
{
struct device *dev = dmab->dev.dev;
struct gen_pool *pool = NULL;
dmab->area = NULL;
dmab->addr = 0;
if (dev->of_node)
pool = of_gen_pool_get(dev->of_node, "iram", 0);
if (!pool)
return;
/* Assign the pool into private_data field */
dmab->private_data = pool;
dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr,
PAGE_SIZE);
}
/**
* snd_free_dev_iram - free allocated specific memory from on-chip internal ram
* @dmab: buffer allocation record to store the allocated data
*/
static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
{
struct gen_pool *pool = dmab->private_data;
if (pool && dmab->area)
gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
#endif /* CONFIG_HAS_DMA */
/*
*
* ALSA generic memory management
*
*/
static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev,
/* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */
static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab,
gfp_t default_gfp)
{
if (!dev)
if (!dmab->dev.dev)
return default_gfp;
else
return (__force gfp_t)(unsigned long)dev;
return (__force gfp_t)(unsigned long)dmab->dev.dev;
}
static int __snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (WARN_ON_ONCE(!ops || !ops->alloc))
return -EINVAL;
return ops->alloc(dmab, size);
}
/**
@ -126,7 +54,7 @@ static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev,
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
struct snd_dma_buffer *dmab)
{
gfp_t gfp;
int err;
if (WARN_ON(!size))
return -ENXIO;
@ -140,43 +68,10 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->area = NULL;
dmab->addr = 0;
dmab->private_data = NULL;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL);
dmab->area = alloc_pages_exact(size, gfp);
break;
case SNDRV_DMA_TYPE_VMALLOC:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM);
dmab->area = __vmalloc(size, gfp);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR
case SNDRV_DMA_TYPE_DEV_IRAM:
snd_malloc_dev_iram(dmab, size);
if (dmab->area)
break;
/* Internal memory might have limited size and no enough space,
* so if we fail to malloc, try to fetch memory traditionally.
*/
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
fallthrough;
#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
case SNDRV_DMA_TYPE_DEV_UC:
snd_malloc_dev_pages(dmab, size);
break;
#endif
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
break;
#endif
default:
pr_err("snd-malloc: invalid device type %d\n", type);
return -ENXIO;
}
if (! dmab->area)
err = __snd_dma_alloc_pages(dmab, size);
if (err < 0)
return err;
if (!dmab->area)
return -ENOMEM;
dmab->bytes = size;
return 0;
@ -217,7 +112,6 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
}
EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
/**
* snd_dma_free_pages - release the allocated buffer
* @dmab: the buffer allocation record to release
@ -226,32 +120,288 @@ EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
*/
void snd_dma_free_pages(struct snd_dma_buffer *dmab)
{
switch (dmab->dev.type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
free_pages_exact(dmab->area, dmab->bytes);
break;
case SNDRV_DMA_TYPE_VMALLOC:
vfree(dmab->area);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR
case SNDRV_DMA_TYPE_DEV_IRAM:
snd_free_dev_iram(dmab);
break;
#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
case SNDRV_DMA_TYPE_DEV_UC:
snd_free_dev_pages(dmab);
break;
#endif
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
snd_free_sgbuf_pages(dmab);
break;
#endif
default:
pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);
}
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->free)
ops->free(dmab);
}
EXPORT_SYMBOL(snd_dma_free_pages);
/**
* snd_dma_buffer_mmap - perform mmap of the given DMA buffer
* @dmab: buffer allocation information
* @area: VM area information
*/
int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->mmap)
return ops->mmap(dmab, area);
else
return -ENOENT;
}
EXPORT_SYMBOL(snd_dma_buffer_mmap);
/**
* snd_sgbuf_get_addr - return the physical address at the corresponding offset
* @dmab: buffer allocation information
* @offset: offset in the ring buffer
*/
dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->get_addr)
return ops->get_addr(dmab, offset);
else
return dmab->addr + offset;
}
EXPORT_SYMBOL(snd_sgbuf_get_addr);
/**
* snd_sgbuf_get_page - return the physical page at the corresponding offset
* @dmab: buffer allocation information
* @offset: offset in the ring buffer
*/
struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->get_page)
return ops->get_page(dmab, offset);
else
return virt_to_page(dmab->area + offset);
}
EXPORT_SYMBOL(snd_sgbuf_get_page);
/**
* snd_sgbuf_get_chunk_size - compute the max chunk size with continuous pages
* on sg-buffer
* @dmab: buffer allocation information
* @ofs: offset in the ring buffer
* @size: the requested size
*/
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->get_chunk_size)
return ops->get_chunk_size(dmab, ofs, size);
else
return size;
}
EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
/*
* Continuous pages allocator
*/
static int snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL);
dmab->area = alloc_pages_exact(size, gfp);
return 0;
}
static void snd_dma_continuous_free(struct snd_dma_buffer *dmab)
{
free_pages_exact(dmab->area, dmab->bytes);
}
static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return remap_pfn_range(area, area->vm_start,
dmab->addr >> PAGE_SHIFT,
area->vm_end - area->vm_start,
area->vm_page_prot);
}
static const struct snd_malloc_ops snd_dma_continuous_ops = {
.alloc = snd_dma_continuous_alloc,
.free = snd_dma_continuous_free,
.mmap = snd_dma_continuous_mmap,
};
/*
* VMALLOC allocator
*/
static int snd_dma_vmalloc_alloc(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL | __GFP_HIGHMEM);
dmab->area = __vmalloc(size, gfp);
return 0;
}
static void snd_dma_vmalloc_free(struct snd_dma_buffer *dmab)
{
vfree(dmab->area);
}
static int snd_dma_vmalloc_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return remap_vmalloc_range(area, dmab->area, 0);
}
static dma_addr_t snd_dma_vmalloc_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
return page_to_phys(vmalloc_to_page(dmab->area + offset)) +
offset % PAGE_SIZE;
}
static struct page *snd_dma_vmalloc_get_page(struct snd_dma_buffer *dmab,
size_t offset)
{
return vmalloc_to_page(dmab->area + offset);
}
static unsigned int
snd_dma_vmalloc_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size)
{
ofs %= PAGE_SIZE;
size += ofs;
if (size > PAGE_SIZE)
size = PAGE_SIZE;
return size - ofs;
}
static const struct snd_malloc_ops snd_dma_vmalloc_ops = {
.alloc = snd_dma_vmalloc_alloc,
.free = snd_dma_vmalloc_free,
.mmap = snd_dma_vmalloc_mmap,
.get_addr = snd_dma_vmalloc_get_addr,
.get_page = snd_dma_vmalloc_get_page,
.get_chunk_size = snd_dma_vmalloc_get_chunk_size,
};
#ifdef CONFIG_HAS_DMA
/*
* IRAM allocator
*/
#ifdef CONFIG_GENERIC_ALLOCATOR
static int snd_dma_iram_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct device *dev = dmab->dev.dev;
struct gen_pool *pool;
if (dev->of_node) {
pool = of_gen_pool_get(dev->of_node, "iram", 0);
/* Assign the pool into private_data field */
dmab->private_data = pool;
dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr,
PAGE_SIZE);
if (dmab->area)
return 0;
}
/* Internal memory might have limited size and no enough space,
* so if we fail to malloc, try to fetch memory traditionally.
*/
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
return __snd_dma_alloc_pages(dmab, size);
}
static void snd_dma_iram_free(struct snd_dma_buffer *dmab)
{
struct gen_pool *pool = dmab->private_data;
if (pool && dmab->area)
gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes);
}
static int snd_dma_iram_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return remap_pfn_range(area, area->vm_start,
dmab->addr >> PAGE_SHIFT,
area->vm_end - area->vm_start,
area->vm_page_prot);
}
static const struct snd_malloc_ops snd_dma_iram_ops = {
.alloc = snd_dma_iram_alloc,
.free = snd_dma_iram_free,
.mmap = snd_dma_iram_mmap,
};
#endif /* CONFIG_GENERIC_ALLOCATOR */
/*
* Coherent device pages allocator
*/
static int snd_dma_dev_alloc(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp_flags;
gfp_flags = GFP_KERNEL
| __GFP_COMP /* compound page lets parts be mapped */
| __GFP_NORETRY /* don't trigger OOM-killer */
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
gfp_flags);
#ifdef CONFIG_X86
if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wc((unsigned long)dmab->area,
PAGE_ALIGN(size) >> PAGE_SHIFT);
#endif
return 0;
}
static void snd_dma_dev_free(struct snd_dma_buffer *dmab)
{
#ifdef CONFIG_X86
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wb((unsigned long)dmab->area,
PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
#endif
dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
}
static int snd_dma_dev_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return dma_mmap_coherent(dmab->dev.dev, area,
dmab->area, dmab->addr, dmab->bytes);
}
static const struct snd_malloc_ops snd_dma_dev_ops = {
.alloc = snd_dma_dev_alloc,
.free = snd_dma_dev_free,
.mmap = snd_dma_dev_mmap,
};
#endif /* CONFIG_HAS_DMA */
/*
* Entry points
*/
static const struct snd_malloc_ops *dma_ops[] = {
[SNDRV_DMA_TYPE_CONTINUOUS] = &snd_dma_continuous_ops,
[SNDRV_DMA_TYPE_VMALLOC] = &snd_dma_vmalloc_ops,
#ifdef CONFIG_HAS_DMA
[SNDRV_DMA_TYPE_DEV] = &snd_dma_dev_ops,
[SNDRV_DMA_TYPE_DEV_UC] = &snd_dma_dev_ops,
#ifdef CONFIG_GENERIC_ALLOCATOR
[SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops,
#endif /* CONFIG_GENERIC_ALLOCATOR */
#endif /* CONFIG_HAS_DMA */
#ifdef CONFIG_SND_DMA_SGBUF
[SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops,
[SNDRV_DMA_TYPE_DEV_UC_SG] = &snd_dma_sg_ops,
#endif
};
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab)
{
if (WARN_ON_ONCE(dmab->dev.type <= SNDRV_DMA_TYPE_UNKNOWN ||
dmab->dev.type >= ARRAY_SIZE(dma_ops)))
return NULL;
return dma_ops[dmab->dev.type];
}

View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-only
#ifndef __MEMALLOC_LOCAL_H
#define __MEMALLOC_LOCAL_H
struct snd_malloc_ops {
int (*alloc)(struct snd_dma_buffer *dmab, size_t size);
void (*free)(struct snd_dma_buffer *dmab);
dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset);
struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset);
unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area);
};
#ifdef CONFIG_SND_DMA_SGBUF
extern const struct snd_malloc_ops snd_dma_sg_ops;
#endif
#endif /* __MEMALLOC_LOCAL_H */

View File

@ -185,7 +185,8 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
int err;
unsigned int index;
if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
err = mixer->get_recsrc(fmixer, &index);
if (err < 0)
return err;
result = 1 << index;
} else {
@ -517,7 +518,8 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -555,7 +557,8 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -620,7 +623,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -636,7 +640,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
if (uinfo->count > 1)
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
if ((res = kctl->put(kctl, uctl)) < 0)
res = kctl->put(kctl, uctl);
if (res < 0)
goto __unalloc;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
@ -661,7 +666,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -681,7 +687,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
} else {
uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
}
if ((res = kctl->put(kctl, uctl)) < 0)
res = kctl->put(kctl, uctl);
if (res < 0)
goto __unalloc;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
@ -809,9 +816,11 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
err = -ENOENT;
goto __unlock;
}
if ((err = kctl->info(kctl, uinfo)) < 0)
err = kctl->info(kctl, uinfo);
if (err < 0)
goto __unlock;
if ((err = kctl->get(kctl, uctl)) < 0)
err = kctl->get(kctl, uctl);
if (err < 0)
goto __unlock;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
@ -860,7 +869,8 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
err = -ENOENT;
goto __unlock;
}
if ((err = kctl->info(kctl, uinfo)) < 0)
err = kctl->info(kctl, uinfo);
if (err < 0)
goto __unlock;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
@ -915,7 +925,8 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
up_read(&card->controls_rwsem);
return -ENOMEM;
}
if ((err = kcontrol->info(kcontrol, info)) < 0) {
err = kcontrol->info(kcontrol, info);
if (err < 0) {
up_read(&card->controls_rwsem);
kfree(info);
return err;
@ -1036,7 +1047,10 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
return 0;
down_read(&mixer->card->controls_rwsem);
if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
kctl = NULL;
if (!ptr->index)
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
if (kctl) {
struct snd_ctl_elem_info *uinfo;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@ -1343,9 +1357,10 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
if (mixer == NULL)
return -ENOMEM;
mutex_init(&mixer->reg_mutex);
if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
&snd_mixer_oss_f_ops, card)) < 0) {
err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
&snd_mixer_oss_f_ops, card);
if (err < 0) {
dev_err(card->dev,
"unable to register OSS mixer device %i:%i\n",
card->number, 0);

View File

@ -955,9 +955,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
if (!direct) {
/* add necessary plugins */
snd_pcm_oss_plugin_clear(substream);
if ((err = snd_pcm_plug_format_plugins(substream,
params,
sparams)) < 0) {
err = snd_pcm_plug_format_plugins(substream, params, sparams);
if (err < 0) {
pcm_dbg(substream->pcm,
"snd_pcm_plug_format_plugins failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
@ -965,7 +964,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
}
if (runtime->oss.plugin_first) {
struct snd_pcm_plugin *plugin;
if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
err = snd_pcm_plugin_build_io(substream, sparams, &plugin);
if (err < 0) {
pcm_dbg(substream->pcm,
"snd_pcm_plugin_build_io failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
@ -1011,7 +1011,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
sw_params->silence_size = frames;
}
if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params);
if (err < 0) {
pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
goto failure;
}
@ -1573,7 +1574,8 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
}
@ -1645,7 +1647,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
goto __direct;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
atomic_inc(&runtime->oss.rw_ref);
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
@ -1711,7 +1714,8 @@ unlock:
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (substream != NULL) {
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
runtime = substream->runtime;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
@ -1758,7 +1762,8 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.rate;
}
@ -1795,7 +1800,8 @@ static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.channels;
}
@ -1805,7 +1811,8 @@ static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.period_bytes;
}
@ -1820,7 +1827,8 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
const struct snd_mask *format_mask;
int fmt;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
if (atomic_read(&substream->mmap_count))
direct = 1;
@ -1890,7 +1898,8 @@ static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.format;
}
@ -2050,11 +2059,13 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (psubstream) {
if ((err = snd_pcm_oss_make_ready(psubstream)) < 0)
err = snd_pcm_oss_make_ready(psubstream);
if (err < 0)
return err;
}
if (csubstream) {
if ((err = snd_pcm_oss_make_ready(csubstream)) < 0)
err = snd_pcm_oss_make_ready(csubstream);
if (err < 0)
return err;
}
if (psubstream) {
@ -2141,7 +2152,8 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream == NULL)
return -EINVAL;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare)
@ -2168,7 +2180,8 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
substream = pcm_oss_file->streams[stream];
if (substream == NULL)
return -EINVAL;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare) {
@ -2239,9 +2252,11 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
return -EINVAL;
runtime = substream->runtime;
if (runtime->oss.params &&
(err = snd_pcm_oss_change_params(substream, false)) < 0)
return err;
if (runtime->oss.params) {
err = snd_pcm_oss_change_params(substream, false);
if (err < 0)
return err;
}
info.fragsize = runtime->oss.period_bytes;
info.fragstotal = runtime->periods;
@ -2601,7 +2616,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDCTL_DSP_SPEED:
if (get_user(res, p))
return -EFAULT;
if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0)
res = snd_pcm_oss_set_rate(pcm_oss_file, res);
if (res < 0)
return res;
return put_user(res, p);
case SOUND_PCM_READ_RATE:
@ -2613,7 +2629,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (get_user(res, p))
return -EFAULT;
res = res > 0 ? 2 : 1;
if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0)
res = snd_pcm_oss_set_channels(pcm_oss_file, res);
if (res < 0)
return res;
return put_user(--res, p);
case SNDCTL_DSP_GETBLKSIZE:
@ -2829,7 +2846,8 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
snd_pcm_state_t ostate;
poll_wait(file, &runtime->sleep, wait);
snd_pcm_stream_lock_irq(csubstream);
if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
ostate = runtime->status->state;
if (ostate != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM;
snd_pcm_stream_unlock_irq(csubstream);
@ -3043,7 +3061,8 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
struct snd_pcm_str *pstr = &pcm->streams[stream];
if (pstr->substream_count == 0)
continue;
if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root);
if (entry) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | 0644;
entry->c.text.read = snd_pcm_oss_proc_read;
@ -3191,7 +3210,8 @@ static int __init alsa_pcm_oss_init(void)
adsp_map[i] = 1;
}
}
if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
err = snd_pcm_notify(&snd_pcm_oss_notify, 0);
if (err < 0)
return err;
return 0;
}

View File

@ -59,7 +59,8 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t
} else {
format = &plugin->dst_format;
}
if ((width = snd_pcm_format_physical_width(format->format)) < 0)
width = snd_pcm_format_physical_width(format->format);
if (width < 0)
return width;
size = frames * format->channels * width;
if (snd_BUG_ON(size % 8))
@ -572,7 +573,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu
}
v = plugin->buf_channels;
*channels = v;
if ((width = snd_pcm_format_physical_width(format->format)) < 0)
width = snd_pcm_format_physical_width(format->format);
if (width < 0)
return width;
nchannels = format->channels;
if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
@ -600,16 +602,17 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
while (plugin) {
if (frames <= 0)
return frames;
if ((next = plugin->next) != NULL) {
next = plugin->next;
if (next) {
snd_pcm_sframes_t frames1 = frames;
if (plugin->dst_frames) {
frames1 = plugin->dst_frames(plugin, frames);
if (frames1 <= 0)
return frames1;
}
if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
err = next->client_channels(next, frames1, &dst_channels);
if (err < 0)
return err;
}
if (err != frames1) {
frames = err;
if (plugin->src_frames) {
@ -621,7 +624,8 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
} else
dst_channels = NULL;
pdprintf("write plugin: %s, %li\n", plugin->name, frames);
if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
if (frames < 0)
return frames;
src_channels = dst_channels;
plugin = next;
@ -643,16 +647,18 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
src_channels = NULL;
plugin = snd_pcm_plug_first(plug);
while (plugin && frames > 0) {
if ((next = plugin->next) != NULL) {
if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
next = plugin->next;
if (next) {
err = plugin->client_channels(plugin, frames, &dst_channels);
if (err < 0)
return err;
}
frames = err;
} else {
dst_channels = dst_channels_final;
}
pdprintf("read plugin: %s, %li\n", plugin->name, frames);
if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
if (frames < 0)
return frames;
plugin = next;
src_channels = dst_channels;

View File

@ -1004,7 +1004,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
substream->pstr->substream_opened--;
}
static ssize_t show_pcm_class(struct device *dev,
static ssize_t pcm_class_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev);
@ -1024,7 +1024,7 @@ static ssize_t show_pcm_class(struct device *dev,
return sprintf(buf, "%s\n", str);
}
static DEVICE_ATTR(pcm_class, 0444, show_pcm_class, NULL);
static DEVICE_ATTR_RO(pcm_class);
static struct attribute *pcm_dev_attrs[] = {
&dev_attr_pcm_class.attr,
NULL

View File

@ -239,7 +239,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime;
int err;
if (! (runtime = substream->runtime))
runtime = substream->runtime;
if (!runtime)
return -ENOTTY;
data = kmalloc(sizeof(*data), GFP_KERNEL);
@ -343,7 +344,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if ((ch = substream->runtime->channels) > 128)
ch = substream->runtime->channels;
if (ch > 128)
return -EINVAL;
if (get_user(buf, &data32->bufs) ||
get_user(frames, &data32->frames))

View File

@ -1778,27 +1778,38 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
EXPORT_SYMBOL(snd_pcm_lib_ioctl);
/**
* snd_pcm_period_elapsed - update the pcm status for the next period
* @substream: the pcm substream instance
* snd_pcm_period_elapsed_under_stream_lock() - update the status of runtime for the next period
* under acquired lock of PCM substream.
* @substream: the instance of pcm substream.
*
* This function is called from the interrupt handler when the
* PCM has processed the period size. It will update the current
* pointer, wake up sleepers, etc.
* This function is called when the batch of audio data frames as the same size as the period of
* buffer is already processed in audio data transmission.
*
* Even if more than one periods have elapsed since the last call, you
* have to call this only once.
* The call of function updates the status of runtime with the latest position of audio data
* transmission, checks overrun and underrun over buffer, awaken user processes from waiting for
* available audio data frames, sampling audio timestamp, and performs stop or drain the PCM
* substream according to configured threshold.
*
* The function is intended to use for the case that PCM driver operates audio data frames under
* acquired lock of PCM substream; e.g. in callback of any operation of &snd_pcm_ops in process
* context. In any interrupt context, it's preferrable to use ``snd_pcm_period_elapsed()`` instead
* since lock of PCM substream should be acquired in advance.
*
* Developer should pay enough attention that some callbacks in &snd_pcm_ops are done by the call of
* function:
*
* - .pointer - to retrieve current position of audio data transmission by frame count or XRUN state.
* - .trigger - with SNDRV_PCM_TRIGGER_STOP at XRUN or DRAINING state.
* - .get_time_info - to retrieve audio time stamp if needed.
*
* Even if more than one periods have elapsed since the last call, you have to call this only once.
*/
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
unsigned long flags;
if (snd_BUG_ON(!substream))
return;
snd_pcm_stream_lock_irqsave(substream, flags);
if (PCM_RUNTIME_CHECK(substream))
goto _unlock;
return;
runtime = substream->runtime;
if (!snd_pcm_running(substream) ||
@ -1811,7 +1822,30 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
#endif
_end:
kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
_unlock:
}
EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
/**
* snd_pcm_period_elapsed() - update the status of runtime for the next period by acquiring lock of
* PCM substream.
* @substream: the instance of PCM substream.
*
* This function is mostly similar to ``snd_pcm_period_elapsed_under_stream_lock()`` except for
* acquiring lock of PCM substream voluntarily.
*
* It's typically called by any type of IRQ handler when hardware IRQ occurs to notify event that
* the batch of audio data frames as the same size as the period of buffer is already processed in
* audio data transmission.
*/
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
{
unsigned long flags;
if (snd_BUG_ON(!substream))
return;
snd_pcm_stream_lock_irqsave(substream, flags);
snd_pcm_period_elapsed_under_stream_lock(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
}
EXPORT_SYMBOL(snd_pcm_period_elapsed);

View File

@ -65,11 +65,6 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream);
void snd_pcm_group_init(struct snd_pcm_group *group);
void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq);
#ifdef CONFIG_SND_DMA_SGBUF
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
unsigned long offset);
#endif
#define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
/* loop over all PCM substreams */

View File

@ -337,27 +337,6 @@ void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
}
EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all);
#ifdef CONFIG_SND_DMA_SGBUF
/*
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
* @offset: the buffer offset
*
* Used as the page callback of PCM ops.
*
* Return: The page struct at the given buffer offset. %NULL on failure.
*/
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset)
{
struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
unsigned int idx = offset >> PAGE_SHIFT;
if (idx >= (unsigned int)sgbuf->pages)
return NULL;
return sgbuf->page_table[idx];
}
#endif /* CONFIG_SND_DMA_SGBUF */
/**
* snd_pcm_lib_malloc_pages - allocate the DMA buffer
* @substream: the substream to allocate the DMA buffer to

View File

@ -266,7 +266,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].signd) < 0)
val = pcm_formats[(INT)format].signd;
if (val < 0)
return -EINVAL;
return val;
}
@ -314,7 +315,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].le) < 0)
val = pcm_formats[(INT)format].le;
if (val < 0)
return -EINVAL;
return val;
}
@ -350,7 +352,8 @@ int snd_pcm_format_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].width) == 0)
val = pcm_formats[(INT)format].width;
if (!val)
return -EINVAL;
return val;
}
@ -368,7 +371,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].phys) == 0)
val = pcm_formats[(INT)format].phys;
if (!val)
return -EINVAL;
return val;
}

View File

@ -768,7 +768,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req))
cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
if ((usecs = period_to_usecs(runtime)) >= 0)
usecs = period_to_usecs(runtime);
if (usecs >= 0)
cpu_latency_qos_add_request(&substream->latency_pm_qos_req,
usecs);
return 0;
@ -2658,7 +2659,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
goto error;
}
if ((err = substream->ops->open(substream)) < 0)
err = substream->ops->open(substream);
if (err < 0)
goto error;
substream->hw_opened = 1;
@ -2799,6 +2801,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
if (snd_BUG_ON(!substream))
return -ENXIO;
pcm = substream->pcm;
/* block until the device gets woken up as it may touch the hardware */
snd_power_wait(pcm->card);
mutex_lock(&pcm->open_mutex);
snd_pcm_release_substream(substream);
kfree(pcm_file);
@ -3193,7 +3199,7 @@ static int snd_pcm_common_ioctl(struct file *file,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
res = snd_power_wait(substream->pcm->card);
if (res < 0)
return res;
@ -3638,24 +3644,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
}
#endif /* coherent mmap */
static inline struct page *
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
{
void *vaddr = substream->runtime->dma_area + ofs;
switch (substream->dma_buffer.dev.type) {
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
return snd_pcm_sgbuf_ops_page(substream, ofs);
#endif /* CONFIG_SND_DMA_SGBUF */
case SNDRV_DMA_TYPE_VMALLOC:
return vmalloc_to_page(vaddr);
default:
return virt_to_page(vaddr);
}
}
/*
* fault callback for mmapping a RAM page
*/
@ -3677,7 +3665,7 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
if (substream->ops->page)
page = substream->ops->page(substream, offset);
else
page = snd_pcm_default_page_ops(substream, offset);
page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset);
if (!page)
return VM_FAULT_SIGBUS;
get_page(page);
@ -3712,22 +3700,9 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
#ifdef CONFIG_GENERIC_ALLOCATOR
if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return remap_pfn_range(area, area->vm_start,
substream->dma_buffer.addr >> PAGE_SHIFT,
area->vm_end - area->vm_start, area->vm_page_prot);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page &&
(substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV ||
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC))
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
area,
substream->runtime->dma_area,
substream->runtime->dma_addr,
substream->runtime->dma_bytes);
if (!substream->ops->page &&
!snd_dma_buffer_mmap(snd_pcm_get_dma_buf(substream), area))
return 0;
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;

View File

@ -680,9 +680,12 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
bool is_input)
{
char *newbuf, *oldbuf;
unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L)
return -EINVAL;
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP && (params->buffer_size & 0x1f) != 0)
return -EINVAL;
if (params->avail_min < 1 || params->avail_min > params->buffer_size)
return -EINVAL;
if (params->buffer_size != runtime->buffer_size) {
@ -720,8 +723,24 @@ EXPORT_SYMBOL(snd_rawmidi_output_params);
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params *params)
{
unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK;
int err;
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
return -EINVAL;
else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
return -EINVAL;
if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
return -EINVAL;
snd_rawmidi_drain_input(substream);
return resize_runtime_buffer(substream->runtime, params, true);
err = resize_runtime_buffer(substream->runtime, params, true);
if (err < 0)
return err;
substream->framing = framing;
substream->clock_type = clock_type;
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_input_params);
@ -963,6 +982,62 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
return -ENOIOCTLCMD;
}
static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
const unsigned char *buffer, int src_count, const struct timespec64 *tstamp)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
struct snd_rawmidi_framing_tstamp *dest_ptr;
struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec };
int dest_frames = 0;
int orig_count = src_count;
int frame_size = sizeof(struct snd_rawmidi_framing_tstamp);
BUILD_BUG_ON(frame_size != 0x20);
if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0))
return -EINVAL;
while (src_count > 0) {
if ((int)(runtime->buffer_size - runtime->avail) < frame_size) {
runtime->xruns += src_count;
break;
}
if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH)
frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH;
else {
frame.length = src_count;
memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH);
}
memcpy(frame.data, buffer, frame.length);
buffer += frame.length;
src_count -= frame.length;
dest_ptr = (struct snd_rawmidi_framing_tstamp *) (runtime->buffer + runtime->hw_ptr);
*dest_ptr = frame;
runtime->avail += frame_size;
runtime->hw_ptr += frame_size;
runtime->hw_ptr %= runtime->buffer_size;
dest_frames++;
}
return orig_count - src_count;
}
static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substream)
{
struct timespec64 ts64 = {0, 0};
switch (substream->clock_type) {
case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW:
ktime_get_raw_ts64(&ts64);
break;
case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC:
ktime_get_ts64(&ts64);
break;
case SNDRV_RAWMIDI_MODE_CLOCK_REALTIME:
ktime_get_real_ts64(&ts64);
break;
}
return ts64;
}
/**
* snd_rawmidi_receive - receive the input data from the device
* @substream: the rawmidi substream
@ -977,6 +1052,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
const unsigned char *buffer, int count)
{
unsigned long flags;
struct timespec64 ts64 = get_framing_tstamp(substream);
int result = 0, count1;
struct snd_rawmidi_runtime *runtime = substream->runtime;
@ -987,8 +1063,11 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
"snd_rawmidi_receive: input is not active!!!\n");
return -EINVAL;
}
spin_lock_irqsave(&runtime->lock, flags);
if (count == 1) { /* special case, faster code */
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
} else if (count == 1) { /* special case, faster code */
substream->bytes++;
if (runtime->avail < runtime->buffer_size) {
runtime->buffer[runtime->hw_ptr++] = buffer[0];
@ -1541,6 +1620,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
struct snd_rawmidi_substream *substream;
struct snd_rawmidi_runtime *runtime;
unsigned long buffer_size, avail, xruns;
unsigned int clock_type;
static const char *clock_names[4] = { "none", "realtime", "monotonic", "monotonic raw" };
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
@ -1596,6 +1677,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Avail : %lu\n"
" Overruns : %lu\n",
buffer_size, avail, xruns);
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
clock_type = substream->clock_type >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT;
if (!snd_BUG_ON(clock_type >= ARRAY_SIZE(clock_names)))
snd_iprintf(buffer,
" Framing : tstamp\n"
" Clock type : %s\n",
clock_names[clock_type]);
}
}
}
}

View File

@ -13,7 +13,8 @@ struct snd_rawmidi_params32 {
u32 buffer_size;
u32 avail_min;
unsigned int no_active_sensing; /* avoid bit-field */
unsigned char reserved[16];
unsigned int mode;
unsigned char reserved[12];
} __attribute__((packed));
static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
@ -25,6 +26,7 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
if (get_user(params.stream, &src->stream) ||
get_user(params.buffer_size, &src->buffer_size) ||
get_user(params.avail_min, &src->avail_min) ||
get_user(params.mode, &src->mode) ||
get_user(val, &src->no_active_sensing))
return -EFAULT;
params.no_active_sensing = val;

View File

@ -67,13 +67,16 @@ static int __init alsa_seq_oss_init(void)
{
int rc;
if ((rc = register_device()) < 0)
rc = register_device();
if (rc < 0)
goto error;
if ((rc = register_proc()) < 0) {
rc = register_proc();
if (rc < 0) {
unregister_device();
goto error;
}
if ((rc = snd_seq_oss_create_client()) < 0) {
rc = snd_seq_oss_create_client();
if (rc < 0) {
unregister_proc();
unregister_device();
goto error;
@ -133,7 +136,8 @@ odev_release(struct inode *inode, struct file *file)
{
struct seq_oss_devinfo *dp;
if ((dp = file->private_data) == NULL)
dp = file->private_data;
if (!dp)
return 0;
mutex_lock(&register_mutex);
@ -226,16 +230,18 @@ register_device(void)
int rc;
mutex_lock(&register_mutex);
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
&seq_oss_f_ops, NULL)) < 0) {
rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
&seq_oss_f_ops, NULL);
if (rc < 0) {
pr_err("ALSA: seq_oss: can't register device seq\n");
mutex_unlock(&register_mutex);
return rc;
}
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
NULL, 0,
&seq_oss_f_ops, NULL)) < 0) {
rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
NULL, 0,
&seq_oss_f_ops, NULL);
if (rc < 0) {
pr_err("ALSA: seq_oss: can't register device music\n");
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
mutex_unlock(&register_mutex);

View File

@ -94,10 +94,10 @@ snd_seq_oss_create_client(void)
port_callback.event_input = receive_announce;
port->kernel = &port_callback;
call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
if ((system_port = port->addr.port) >= 0) {
if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) {
struct snd_seq_port_subscribe subs;
system_port = port->addr.port;
memset(&subs, 0, sizeof(subs));
subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
@ -354,7 +354,8 @@ alloc_seq_queue(struct seq_oss_devinfo *dp)
qinfo.owner = system_client;
qinfo.locked = 1;
strcpy(qinfo.name, "OSS Sequencer Emulation");
if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0)
rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo);
if (rc < 0)
return rc;
dp->queue = qinfo.queue;
return 0;
@ -485,7 +486,8 @@ snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
for (i = 0; i < num_clients; i++) {
snd_iprintf(buf, "\nApplication %d: ", i);
if ((dp = client_table[i]) == NULL) {
dp = client_table[i];
if (!dp) {
snd_iprintf(buf, "*empty*\n");
continue;
}

View File

@ -152,7 +152,8 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
/*
* look for the identical slot
*/
if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) {
mdev = find_slot(pinfo->addr.client, pinfo->addr.port);
if (mdev) {
/* already exists */
snd_use_lock_free(&mdev->use_lock);
return 0;
@ -218,7 +219,8 @@ snd_seq_oss_midi_check_exit_port(int client, int port)
unsigned long flags;
int index;
if ((mdev = find_slot(client, port)) != NULL) {
mdev = find_slot(client, port);
if (mdev) {
spin_lock_irqsave(&register_lock, flags);
midi_devs[mdev->seq_device] = NULL;
spin_unlock_irqrestore(&register_lock, flags);
@ -250,7 +252,8 @@ snd_seq_oss_midi_clear_all(void)
spin_lock_irqsave(&register_lock, flags);
for (i = 0; i < max_midi_devs; i++) {
if ((mdev = midi_devs[i]) != NULL) {
mdev = midi_devs[i];
if (mdev) {
snd_midi_event_free(mdev->coder);
kfree(mdev);
midi_devs[i] = NULL;
@ -318,7 +321,8 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
struct seq_oss_midi *mdev;
struct snd_seq_port_subscribe subs;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
/* already used? */
@ -384,7 +388,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
struct seq_oss_midi *mdev;
struct snd_seq_port_subscribe subs;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
if (! mdev->opened || mdev->devinfo != dp) {
snd_use_lock_free(&mdev->use_lock);
@ -421,7 +426,8 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
struct seq_oss_midi *mdev;
int mode;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return 0;
mode = 0;
@ -443,7 +449,8 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return;
if (! mdev->opened) {
snd_use_lock_free(&mdev->use_lock);
@ -491,7 +498,8 @@ snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_ad
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return;
addr->client = mdev->client;
addr->port = mdev->port;
@ -511,7 +519,8 @@ snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
if (dp->readq == NULL)
return 0;
if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL)
mdev = find_slot(ev->source.client, ev->source.port);
if (!mdev)
return 0;
if (! (mdev->opened & PERM_READ)) {
snd_use_lock_free(&mdev->use_lock);
@ -623,7 +632,8 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
@ -642,7 +652,8 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENXIO;
inf->device = dev;
inf->dev_type = 0; /* FIXME: ?? */

View File

@ -132,7 +132,8 @@ snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count,
}
/* insert queue */
if ((err = insert_queue(dp, &rec, opt)) < 0)
err = insert_queue(dp, &rec, opt);
if (err < 0)
break;
result += ev_size;

View File

@ -451,7 +451,8 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
if (info->is_midi)
return 0;
if ((rec = get_synthdev(dp, dev)) == NULL)
rec = get_synthdev(dp, dev);
if (!rec)
return -ENXIO;
if (rec->oper.load_patch == NULL)
@ -569,7 +570,8 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u
info = get_synthinfo_nospec(dp, dev);
if (!info || info->is_midi)
return -ENXIO;
if ((rec = get_synthdev(dp, dev)) == NULL)
rec = get_synthdev(dp, dev);
if (!rec)
return -ENXIO;
if (rec->oper.ioctl == NULL)
rc = -ENXIO;
@ -619,7 +621,8 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
inf->device = dev;
strscpy(inf->name, minf.name, sizeof(inf->name));
} else {
if ((rec = get_synthdev(dp, dev)) == NULL)
rec = get_synthdev(dp, dev);
if (!rec)
return -ENXIO;
inf->synth_type = rec->synth_type;
inf->synth_subtype = rec->synth_subtype;

View File

@ -27,7 +27,8 @@ snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
struct seq_oss_writeq *q;
struct snd_seq_client_pool pool;
if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
q = kzalloc(sizeof(*q), GFP_KERNEL);
if (!q)
return NULL;
q->dp = dp;
q->maxlen = maxlen;

View File

@ -416,7 +416,10 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
if (snd_BUG_ON(!client))
return -ENXIO;
if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
if (!client->accept_input)
return -ENXIO;
fifo = client->data.user.fifo;
if (!fifo)
return -ENXIO;
if (atomic_read(&fifo->overflow) > 0) {
@ -435,9 +438,9 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
int nonblock;
nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) {
err = snd_seq_fifo_cell_out(fifo, &cell, nonblock);
if (err < 0)
break;
}
if (snd_seq_ev_is_variable(&cell->event)) {
struct snd_seq_event tmpev;
tmpev = cell->event;
@ -970,7 +973,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
return err;
/* we got a cell. enqueue it. */
if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) {
err = snd_seq_enqueue_event(cell, atomic, hop);
if (err < 0) {
snd_seq_cell_free(cell);
return err;
}
@ -1312,7 +1316,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
return -EINVAL;
}
if (client->type == KERNEL_CLIENT) {
if ((callback = info->kernel) != NULL) {
callback = info->kernel;
if (callback) {
if (callback->owner)
port->owner = callback->owner;
port->private_data = callback->private_data;
@ -1466,13 +1471,17 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
struct snd_seq_client *receiver = NULL, *sender = NULL;
struct snd_seq_client_port *sport = NULL, *dport = NULL;
if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
receiver = snd_seq_client_use_ptr(subs->dest.client);
if (!receiver)
goto __end;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
goto __end;
if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
dport = snd_seq_port_use_ptr(receiver, subs->dest.port);
if (!dport)
goto __end;
result = check_subscription_permission(client, sport, dport, subs);
@ -1508,13 +1517,17 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
struct snd_seq_client *receiver = NULL, *sender = NULL;
struct snd_seq_client_port *sport = NULL, *dport = NULL;
if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
receiver = snd_seq_client_use_ptr(subs->dest.client);
if (!receiver)
goto __end;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
goto __end;
if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
dport = snd_seq_port_use_ptr(receiver, subs->dest.port);
if (!dport)
goto __end;
result = check_subscription_permission(client, sport, dport, subs);
@ -1926,9 +1939,11 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
struct snd_seq_client_port *sport = NULL;
result = -EINVAL;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
goto __end;
result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
subs);
@ -1955,9 +1970,11 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
struct list_head *p;
int i;
if ((cptr = snd_seq_client_use_ptr(subs->root.client)) == NULL)
cptr = snd_seq_client_use_ptr(subs->root.client);
if (!cptr)
goto __end;
if ((port = snd_seq_port_use_ptr(cptr, subs->root.port)) == NULL)
port = snd_seq_port_use_ptr(cptr, subs->root.port);
if (!port)
goto __end;
switch (subs->type) {

View File

@ -109,7 +109,8 @@ create_port(int idx, int type)
struct snd_seq_port_callback pcb;
struct snd_seq_dummy_port *rec;
if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL)
rec = kzalloc(sizeof(*rec), GFP_KERNEL);
if (!rec)
return NULL;
rec->client = my_client;

View File

@ -143,7 +143,8 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f)
{
struct snd_seq_event_cell *cell;
if ((cell = f->head) != NULL) {
cell = f->head;
if (cell) {
f->head = cell->next;
/* reset tail if this was the last element */

View File

@ -69,7 +69,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
int len, err;
struct snd_seq_event_cell *cell;
if ((len = get_var_len(event)) <= 0)
len = get_var_len(event);
if (len <= 0)
return len;
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
@ -133,7 +134,8 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
int len, newlen;
int err;
if ((len = get_var_len(event)) < 0)
len = get_var_len(event);
if (len < 0)
return len;
newlen = len;
if (size_aligned > 0)

View File

@ -101,7 +101,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
if (snd_BUG_ON(!substream || !buf))
return -EINVAL;
runtime = substream->runtime;
if ((tmp = runtime->avail) < count) {
tmp = runtime->avail;
if (tmp < count) {
if (printk_ratelimit())
pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
return -ENOMEM;
@ -167,10 +168,11 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
struct snd_rawmidi_params params;
/* open midi port */
if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
&msynth->input_rfile)) < 0) {
err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
&msynth->input_rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
return err;
}
@ -178,7 +180,8 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
memset(&params, 0, sizeof(params));
params.avail_min = 1;
params.buffer_size = input_buffer_size;
if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, &params)) < 0) {
err = snd_rawmidi_input_params(msynth->input_rfile.input, &params);
if (err < 0) {
snd_rawmidi_kernel_release(&msynth->input_rfile);
return err;
}
@ -209,10 +212,11 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
struct snd_rawmidi_params params;
/* open midi port */
if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile)) < 0) {
err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
return err;
}
@ -220,7 +224,8 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
params.avail_min = 1;
params.buffer_size = output_buffer_size;
params.no_active_sensing = 1;
if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, &params)) < 0) {
err = snd_rawmidi_output_params(msynth->output_rfile.output, &params);
if (err < 0) {
snd_rawmidi_kernel_release(&msynth->output_rfile);
return err;
}

View File

@ -222,7 +222,8 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) != NULL) {
q = queueptr(i);
if (q) {
if (strncmp(q->name, name, sizeof(q->name)) == 0)
return q;
queuefree(q);
@ -432,7 +433,8 @@ int snd_seq_queue_timer_open(int queueid)
if (queue == NULL)
return -EINVAL;
tmr = queue->timer;
if ((result = snd_seq_timer_open(queue)) < 0) {
result = snd_seq_timer_open(queue);
if (result < 0) {
snd_seq_timer_defaults(tmr);
result = snd_seq_timer_open(queue);
}
@ -548,7 +550,8 @@ void snd_seq_queue_client_leave(int client)
/* delete own queues from queue list */
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queue_list_remove(i, client)) != NULL)
q = queue_list_remove(i, client);
if (q)
queue_delete(q);
}
@ -556,7 +559,8 @@ void snd_seq_queue_client_leave(int client)
* they are not owned by this client
*/
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
if (test_bit(client, q->clients_bitmap)) {
snd_seq_prioq_leave(q->tickq, client, 0);
@ -578,7 +582,8 @@ void snd_seq_queue_client_leave_cells(int client)
struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
snd_seq_prioq_leave(q->tickq, client, 0);
snd_seq_prioq_leave(q->timeq, client, 0);
@ -593,7 +598,8 @@ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info)
struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
if (test_bit(client, q->clients_bitmap) &&
(! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) ||
@ -724,7 +730,8 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
int owner;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
tmr = q->timer;

View File

@ -482,10 +482,11 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
int err;
*rrmidi = NULL;
if ((err = snd_rawmidi_new(card, "VirMidi", device,
16, /* may be configurable */
16, /* may be configurable */
&rmidi)) < 0)
err = snd_rawmidi_new(card, "VirMidi", device,
16, /* may be configurable */
16, /* may be configurable */
&rmidi);
if (err < 0)
return err;
strcpy(rmidi->name, rmidi->id);
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);

View File

@ -10,20 +10,34 @@
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <sound/memalloc.h>
#include "memalloc_local.h"
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table; /* address table */
struct page **page_table; /* page table (for vmap/vunmap) */
struct device *dev;
};
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
#define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN)
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
static void snd_dma_sg_free(struct snd_dma_buffer *dmab)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
struct snd_dma_buffer tmpb;
int i;
if (! sgbuf)
return -EINVAL;
if (!sgbuf)
return;
vunmap(dmab->area);
dmab->area = NULL;
@ -45,15 +59,11 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
kfree(sgbuf->page_table);
kfree(sgbuf);
dmab->private_data = NULL;
return 0;
}
#define MAX_ALLOC_PAGES 32
void *snd_malloc_sgbuf_pages(struct device *device,
size_t size, struct snd_dma_buffer *dmab,
size_t *res_size)
static int snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct snd_sg_buf *sgbuf;
unsigned int i, pages, chunk, maxpages;
@ -63,18 +73,16 @@ void *snd_malloc_sgbuf_pages(struct device *device,
int type = SNDRV_DMA_TYPE_DEV;
pgprot_t prot = PAGE_KERNEL;
dmab->area = NULL;
dmab->addr = 0;
dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (! sgbuf)
return NULL;
if (!sgbuf)
return -ENOMEM;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
type = SNDRV_DMA_TYPE_DEV_UC;
#ifdef pgprot_noncached
prot = pgprot_noncached(PAGE_KERNEL);
#endif
}
sgbuf->dev = device;
sgbuf->dev = dmab->dev.dev;
pages = snd_sgbuf_aligned_pages(size);
sgbuf->tblsize = sgbuf_align_table(pages);
table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
@ -94,12 +102,10 @@ void *snd_malloc_sgbuf_pages(struct device *device,
if (chunk > maxpages)
chunk = maxpages;
chunk <<= PAGE_SHIFT;
if (snd_dma_alloc_pages_fallback(type, device,
if (snd_dma_alloc_pages_fallback(type, dmab->dev.dev,
chunk, &tmpb) < 0) {
if (!sgbuf->pages)
goto _failed;
if (!res_size)
goto _failed;
size = sgbuf->pages * PAGE_SIZE;
break;
}
@ -124,27 +130,42 @@ void *snd_malloc_sgbuf_pages(struct device *device,
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
if (! dmab->area)
goto _failed;
if (res_size)
*res_size = sgbuf->size;
return dmab->area;
return 0;
_failed:
snd_free_sgbuf_pages(dmab); /* free the table */
return NULL;
snd_dma_sg_free(dmab); /* free the table */
return -ENOMEM;
}
/*
* compute the max chunk size with continuous pages on sg-buffer
*/
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size)
static dma_addr_t snd_dma_sg_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
dma_addr_t addr;
addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
addr &= ~((dma_addr_t)PAGE_SIZE - 1);
return addr + offset % PAGE_SIZE;
}
static struct page *snd_dma_sg_get_page(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
unsigned int idx = offset >> PAGE_SHIFT;
if (idx >= (unsigned int)sgbuf->pages)
return NULL;
return sgbuf->page_table[idx];
}
static unsigned int snd_dma_sg_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs,
unsigned int size)
{
struct snd_sg_buf *sg = dmab->private_data;
unsigned int start, end, pg;
if (!sg)
return size;
start = ofs >> PAGE_SHIFT;
end = (ofs + size - 1) >> PAGE_SHIFT;
/* check page continuity */
@ -160,4 +181,11 @@ unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
/* ok, all on continuous pages */
return size;
}
EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
const struct snd_malloc_ops snd_dma_sg_ops = {
.alloc = snd_dma_sg_alloc,
.free = snd_dma_sg_free,
.get_addr = snd_dma_sg_get_addr,
.get_page = snd_dma_sg_get_page,
.get_chunk_size = snd_dma_sg_get_chunk_size,
};

View File

@ -357,7 +357,8 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
mutex_lock(&sound_mutex);
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
if (!(mptr = snd_minors[minor]))
mptr = snd_minors[minor];
if (!mptr)
continue;
if (mptr->card >= 0) {
if (mptr->device >= 0)

View File

@ -217,7 +217,8 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
mutex_lock(&sound_oss_mutex);
for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
if (!(mptr = snd_oss_minors[minor]))
mptr = snd_oss_minors[minor];
if (!mptr)
continue;
if (mptr->card >= 0)
snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", minor,

View File

@ -104,7 +104,8 @@ static int snd_mpu401_probe(struct platform_device *devptr)
err = snd_mpu401_create(&devptr->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
return err;
}
@ -182,7 +183,8 @@ static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
err = snd_mpu401_create(&pnp_dev->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
return err;
}
@ -227,7 +229,8 @@ static int __init alsa_card_mpu401_init(void)
{
int i, err;
if ((err = platform_driver_register(&snd_mpu401_driver)) < 0)
err = platform_driver_register(&snd_mpu401_driver);
if (err < 0)
return err;
for (i = 0; i < SNDRV_CARDS; i++) {

View File

@ -271,8 +271,11 @@ static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream)
int err;
mpu = substream->rmidi->private_data;
if (mpu->open_input && (err = mpu->open_input(mpu)) < 0)
return err;
if (mpu->open_input) {
err = mpu->open_input(mpu);
if (err < 0)
return err;
}
if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) {
if (snd_mpu401_do_reset(mpu) < 0)
goto error_out;
@ -293,8 +296,11 @@ static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream)
int err;
mpu = substream->rmidi->private_data;
if (mpu->open_output && (err = mpu->open_output(mpu)) < 0)
return err;
if (mpu->open_output) {
err = mpu->open_output(mpu);
if (err < 0)
return err;
}
if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
if (snd_mpu401_do_reset(mpu) < 0)
goto error_out;
@ -524,8 +530,9 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
if ((err = snd_rawmidi_new(card, "MPU-401U", device,
out_enable, in_enable, &rmidi)) < 0)
err = snd_rawmidi_new(card, "MPU-401U", device,
out_enable, in_enable, &rmidi);
if (err < 0)
return err;
mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
if (!mpu) {

View File

@ -566,7 +566,8 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
*/
static int snd_mtpav_get_ISA(struct mtpav *mcard)
{
if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) {
mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI");
if (!mcard->res_port) {
snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
return -EBUSY;
}
@ -628,10 +629,11 @@ static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
hwports = 8;
mcard->num_ports = hwports;
if ((rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
&mcard->rmidi)) < 0)
rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
&mcard->rmidi);
if (rval < 0)
return rval;
rawmidi = mcard->rmidi;
rawmidi->private_data = mcard;
@ -744,7 +746,8 @@ static int __init alsa_card_mtpav_init(void)
{
int err;
if ((err = platform_driver_register(&snd_mtpav_driver)) < 0)
err = platform_driver_register(&snd_mtpav_driver);
if (err < 0)
return err;
device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0);

View File

@ -950,7 +950,8 @@ static int snd_mts64_probe(struct platform_device *pdev)
goto free_pardev;
}
if ((err = snd_mts64_create(card, pardev, &mts)) < 0) {
err = snd_mts64_create(card, pardev, &mts);
if (err < 0) {
snd_printd("Cannot create main component\n");
goto release_pardev;
}
@ -963,19 +964,22 @@ static int snd_mts64_probe(struct platform_device *pdev)
goto __err;
}
if ((err = snd_mts64_rawmidi_create(card)) < 0) {
err = snd_mts64_rawmidi_create(card);
if (err < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* init device */
if ((err = mts64_device_init(p)) < 0)
err = mts64_device_init(p);
if (err < 0)
goto __err;
platform_set_drvdata(pdev, card);
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_printd("Cannot register card\n");
goto __err;
}
@ -1031,7 +1035,8 @@ static int __init snd_mts64_module_init(void)
{
int err;
if ((err = platform_driver_register(&snd_mts64_driver)) < 0)
err = platform_driver_register(&snd_mts64_driver);
if (err < 0)
return err;
if (parport_register_driver(&mts64_parport_driver) != 0) {

View File

@ -243,7 +243,8 @@ static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no)
tid.card = opl3->card->number;
tid.device = timer_no;
tid.subdevice = 0;
if ((err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer)) >= 0) {
err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer);
if (err >= 0) {
strcpy(timer->name, "AdLib timer #1");
timer->private_data = opl3;
timer->hw = snd_opl3_timer1;
@ -263,7 +264,8 @@ static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no)
tid.card = opl3->card->number;
tid.device = timer_no;
tid.subdevice = 0;
if ((err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer)) >= 0) {
err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer);
if (err >= 0) {
strcpy(timer->name, "AdLib timer #2");
timer->private_data = opl3;
timer->hw = snd_opl3_timer2;
@ -348,7 +350,8 @@ int snd_opl3_new(struct snd_card *card,
spin_lock_init(&opl3->reg_lock);
spin_lock_init(&opl3->timer_lock);
if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops);
if (err < 0) {
snd_opl3_free(opl3);
return err;
}
@ -396,19 +399,23 @@ int snd_opl3_create(struct snd_card *card,
int err;
*ropl3 = NULL;
if ((err = snd_opl3_new(card, hardware, &opl3)) < 0)
err = snd_opl3_new(card, hardware, &opl3);
if (err < 0)
return err;
if (! integrated) {
if ((opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)")) == NULL) {
opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)");
if (!opl3->res_l_port) {
snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port);
snd_device_free(card, opl3);
return -EBUSY;
}
if (r_port != 0 &&
(opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)")) == NULL) {
snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port);
snd_device_free(card, opl3);
return -EBUSY;
if (r_port != 0) {
opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)");
if (!opl3->res_r_port) {
snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port);
snd_device_free(card, opl3);
return -EBUSY;
}
}
}
opl3->l_port = l_port;
@ -423,7 +430,8 @@ int snd_opl3_create(struct snd_card *card,
break;
default:
opl3->command = &snd_opl2_command;
if ((err = snd_opl3_detect(opl3)) < 0) {
err = snd_opl3_detect(opl3);
if (err < 0) {
snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx\n",
opl3->l_port, opl3->r_port);
snd_device_free(card, opl3);
@ -449,11 +457,14 @@ int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
{
int err;
if (timer1_dev >= 0)
if ((err = snd_opl3_timer1_init(opl3, timer1_dev)) < 0)
if (timer1_dev >= 0) {
err = snd_opl3_timer1_init(opl3, timer1_dev);
if (err < 0)
return err;
}
if (timer2_dev >= 0) {
if ((err = snd_opl3_timer2_init(opl3, timer2_dev)) < 0) {
err = snd_opl3_timer2_init(opl3, timer2_dev);
if (err < 0) {
snd_device_free(opl3->card, opl3->timer1);
opl3->timer1 = NULL;
return err;
@ -477,7 +488,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
/* create hardware dependent device (direct FM) */
if ((err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw)) < 0) {
err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw);
if (err < 0) {
snd_device_free(card, opl3);
return err;
}

View File

@ -180,8 +180,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
if (vp2->state == SNDRV_OPL3_ST_ON_2OP) {
/* kill two voices, EXPENSIVE */
bp++;
voice_time = (voice_time > vp->time) ?
voice_time : vp->time;
voice_time = max(voice_time, vp2->time);
}
} else {
/* allocate 2op voice */

View File

@ -136,7 +136,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
if (snd_BUG_ON(!arg))
return -ENXIO;
if ((err = snd_opl3_synth_setup(opl3)) < 0)
err = snd_opl3_synth_setup(opl3);
if (err < 0)
return err;
/* fill the argument data */
@ -144,7 +145,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
arg->addr.client = opl3->oss_chset->client;
arg->addr.port = opl3->oss_chset->port;
if ((err = snd_opl3_synth_use_inc(opl3)) < 0)
err = snd_opl3_synth_use_inc(opl3);
if (err < 0)
return err;
opl3->synth_mode = SNDRV_OPL3_MODE_SYNTH;

View File

@ -92,7 +92,8 @@ static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe
struct snd_opl3 *opl3 = private_data;
int err;
if ((err = snd_opl3_synth_setup(opl3)) < 0)
err = snd_opl3_synth_setup(opl3);
if (err < 0)
return err;
if (use_internal_drums) {
@ -107,7 +108,8 @@ static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe
}
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
if ((err = snd_opl3_synth_use_inc(opl3)) < 0)
err = snd_opl3_synth_use_inc(opl3);
if (err < 0)
return err;
}
opl3->synth_mode = SNDRV_OPL3_MODE_SEQ;
@ -227,7 +229,8 @@ static int snd_opl3_seq_probe(struct device *_dev)
if (client < 0)
return client;
if ((err = snd_opl3_synth_create_port(opl3)) < 0) {
err = snd_opl3_synth_create_port(opl3);
if (err < 0) {
snd_seq_delete_kernel_client(client);
opl3->seq_client = -1;
return err;

View File

@ -749,7 +749,8 @@ static int snd_portman_probe(struct platform_device *pdev)
goto free_pardev;
}
if ((err = portman_create(card, pardev, &pm)) < 0) {
err = portman_create(card, pardev, &pm);
if (err < 0) {
snd_printd("Cannot create main component\n");
goto release_pardev;
}
@ -762,19 +763,22 @@ static int snd_portman_probe(struct platform_device *pdev)
goto __err;
}
if ((err = snd_portman_rawmidi_create(card)) < 0) {
err = snd_portman_rawmidi_create(card);
if (err < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* init device */
if ((err = portman_device_init(pm)) < 0)
err = portman_device_init(pm);
if (err < 0)
goto __err;
platform_set_drvdata(pdev, card);
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_printd("Cannot register card\n");
goto __err;
}
@ -831,7 +835,8 @@ static int __init snd_portman_module_init(void)
{
int err;
if ((err = platform_driver_register(&snd_portman_driver)) < 0)
err = platform_driver_register(&snd_portman_driver);
if (err < 0)
return err;
if (parport_register_driver(&portman_parport_driver) != 0) {

View File

@ -783,7 +783,8 @@ static int snd_uart16550_create(struct snd_card *card,
int err;
if ((uart = kzalloc(sizeof(*uart), GFP_KERNEL)) == NULL)
uart = kzalloc(sizeof(*uart), GFP_KERNEL);
if (!uart)
return -ENOMEM;
uart->adaptor = adaptor;
uart->card = card;
@ -792,7 +793,8 @@ static int snd_uart16550_create(struct snd_card *card,
uart->base = iobase;
uart->drop_on_full = droponfull;
if ((err = snd_uart16550_detect(uart)) <= 0) {
err = snd_uart16550_detect(uart);
if (err <= 0) {
printk(KERN_ERR "no UART detected at 0x%lx\n", iobase);
snd_uart16550_free(uart);
return -ENODEV;
@ -818,7 +820,8 @@ static int snd_uart16550_create(struct snd_card *card,
uart->timer_running = 0;
/* Register device */
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops)) < 0) {
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops);
if (err < 0) {
snd_uart16550_free(uart);
return err;
}
@ -932,14 +935,10 @@ static int snd_serial_probe(struct platform_device *devptr)
strcpy(card->driver, "Serial");
strcpy(card->shortname, "Serial MIDI (UART16550A)");
if ((err = snd_uart16550_create(card,
port[dev],
irq[dev],
speed[dev],
base[dev],
adaptor[dev],
droponfull[dev],
&uart)) < 0)
err = snd_uart16550_create(card, port[dev], irq[dev], speed[dev],
base[dev], adaptor[dev], droponfull[dev],
&uart);
if (err < 0)
goto _err;
err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);
@ -952,7 +951,8 @@ static int snd_serial_probe(struct platform_device *devptr)
uart->base,
uart->irq);
if ((err = snd_card_register(card)) < 0)
err = snd_card_register(card);
if (err < 0)
goto _err;
platform_set_drvdata(devptr, card);
@ -992,7 +992,8 @@ static int __init alsa_card_serial_init(void)
{
int i, cards, err;
if ((err = platform_driver_register(&snd_serial_driver)) < 0)
err = platform_driver_register(&snd_serial_driver);
if (err < 0)
return err;
cards = 0;

View File

@ -110,20 +110,25 @@ static int vx_transfer_end(struct vx_core *chip, int cmd)
{
int err;
if ((err = vx_reset_chk(chip)) < 0)
err = vx_reset_chk(chip);
if (err < 0)
return err;
/* irq MESS_READ/WRITE_END */
if ((err = vx_send_irq_dsp(chip, cmd)) < 0)
err = vx_send_irq_dsp(chip, cmd);
if (err < 0)
return err;
/* Wait CHK = 1 */
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
/* If error, Read RX */
if ((err = vx_inb(chip, ISR)) & ISR_ERR) {
if ((err = vx_wait_for_rx_full(chip)) < 0) {
err = vx_inb(chip, ISR);
if (err & ISR_ERR) {
err = vx_wait_for_rx_full(chip);
if (err < 0) {
snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n");
return err;
}
@ -232,7 +237,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
if (chip->chip_status & VX_STAT_IS_STALE)
return -EBUSY;
if ((err = vx_reset_chk(chip)) < 0) {
err = vx_reset_chk(chip);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n");
return err;
}
@ -254,7 +260,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
rmh->Cmd[0] &= MASK_1_WORD_COMMAND;
/* Wait for TX empty */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_EMPTY);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n");
return err;
}
@ -265,18 +272,21 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
vx_outb(chip, TXL, rmh->Cmd[0] & 0xff);
/* Trigger irq MESSAGE */
if ((err = vx_send_irq_dsp(chip, IRQ_MESSAGE)) < 0) {
err = vx_send_irq_dsp(chip, IRQ_MESSAGE);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n");
return err;
}
/* Wait for CHK = 1 */
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
/* If error, get error value from RX */
if (vx_inb(chip, ISR) & ISR_ERR) {
if ((err = vx_wait_for_rx_full(chip)) < 0) {
err = vx_wait_for_rx_full(chip);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n");
return err;
}
@ -292,7 +302,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
if (rmh->LgCmd > 1) {
for (i = 1; i < rmh->LgCmd; i++) {
/* Wait for TX ready */
if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_READY);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n");
return err;
}
@ -303,13 +314,15 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
vx_outb(chip, TXL, rmh->Cmd[i] & 0xff);
/* Trigger irq MESS_READ_NEXT */
if ((err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT)) < 0) {
err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n");
return err;
}
}
/* Wait for TX empty */
if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_READY);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n");
return err;
}
@ -362,17 +375,21 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd)
#if 0
printk(KERN_DEBUG "send_rih: cmd = 0x%x\n", cmd);
#endif
if ((err = vx_reset_chk(chip)) < 0)
err = vx_reset_chk(chip);
if (err < 0)
return err;
/* send the IRQ */
if ((err = vx_send_irq_dsp(chip, cmd)) < 0)
err = vx_send_irq_dsp(chip, cmd);
if (err < 0)
return err;
/* Wait CHK = 1 */
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
/* If error, read RX */
if (vx_inb(chip, ISR) & ISR_ERR) {
if ((err = vx_wait_for_rx_full(chip)) < 0)
err = vx_wait_for_rx_full(chip);
if (err < 0)
return err;
err = vx_inb(chip, RXH) << 16;
err |= vx_inb(chip, RXM) << 8;
@ -648,7 +665,8 @@ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot)
vx_reset_board(chip, cold_reset);
vx_validate_irq(chip, 0);
if ((err = snd_vx_load_boot_image(chip, boot)) < 0)
err = snd_vx_load_boot_image(chip, boot);
if (err < 0)
return err;
msleep(10);
@ -678,7 +696,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
for (i = 0; i < dsp->size; i += 3) {
image = dsp->data + i;
/* Wait DSP ready for a new read */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_EMPTY);
if (err < 0) {
printk(KERN_ERR
"dsp loading error at position %d\n", i);
return err;
@ -698,7 +717,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
msleep(200);
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
vx_toggle_dac_mute(chip, 0);

View File

@ -78,15 +78,19 @@ int snd_vx_setup_firmware(struct vx_core *chip)
/* ok, we reached to the last one */
/* create the devices if not built yet */
if ((err = snd_vx_pcm_new(chip)) < 0)
err = snd_vx_pcm_new(chip);
if (err < 0)
return err;
if ((err = snd_vx_mixer_new(chip)) < 0)
err = snd_vx_mixer_new(chip);
if (err < 0)
return err;
if (chip->ops->add_controls)
if ((err = chip->ops->add_controls(chip)) < 0)
if (chip->ops->add_controls) {
err = chip->ops->add_controls(chip);
if (err < 0)
return err;
}
chip->chip_status |= VX_STAT_DEVICE_INIT;
chip->chip_status |= VX_STAT_CHIP_INIT;

View File

@ -910,7 +910,8 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp = vx_control_output_level;
temp.index = i;
temp.tlv.p = chip->hw->output_level_db_scale;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
@ -921,22 +922,26 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp.index = i;
temp.name = "PCM Playback Volume";
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
temp = vx_control_output_switch;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
temp = vx_control_monitor_gain;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
temp = vx_control_monitor_switch;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
for (i = 0; i < chip->hw->num_outs; i++) {
@ -944,20 +949,25 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp.index = i;
temp.name = "PCM Capture Volume";
temp.private_value = (i * 2) | (1 << 8);
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
/* Audio source */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip));
if (err < 0)
return err;
/* clock mode */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip));
if (err < 0)
return err;
/* IEC958 controls */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip));
if (err < 0)
return err;
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip));
if (err < 0)
return err;
/* VU, peak, saturation meters */
for (c = 0; c < 2; c++) {
@ -968,7 +978,8 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp = vx_control_saturation;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
sprintf(name, "%s VU Meter", dir[c]);
@ -976,14 +987,16 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp.index = i;
temp.name = name;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
sprintf(name, "%s Peak Meter", dir[c]);
temp = vx_control_peak_meter;
temp.index = i;
temp.name = name;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
}

View File

@ -341,10 +341,12 @@ static int vx_toggle_pipe(struct vx_core *chip, struct vx_pipe *pipe, int state)
}
}
if ((err = vx_conf_pipe(chip, pipe)) < 0)
err = vx_conf_pipe(chip, pipe);
if (err < 0)
return err;
if ((err = vx_send_irqa(chip)) < 0)
err = vx_send_irqa(chip);
if (err < 0)
return err;
/* If it completes successfully, wait for the pipes
@ -680,8 +682,9 @@ static void vx_pcm_playback_transfer(struct vx_core *chip,
if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
return;
for (i = 0; i < nchunks; i++) {
if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,
chip->ibl.size)) < 0)
err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,
chip->ibl.size);
if (err < 0)
return;
}
}
@ -698,7 +701,8 @@ static void vx_pcm_playback_update(struct vx_core *chip,
struct snd_pcm_runtime *runtime = subs->runtime;
if (pipe->running && ! (chip->chip_status & VX_STAT_IS_STALE)) {
if ((err = vx_update_pipe_position(chip, runtime, pipe)) < 0)
err = vx_update_pipe_position(chip, runtime, pipe);
if (err < 0)
return;
if (pipe->transferred >= (int)runtime->period_size) {
pipe->transferred %= runtime->period_size;
@ -747,11 +751,13 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
pipe->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if ((err = vx_toggle_pipe(chip, pipe, 0)) < 0)
err = vx_toggle_pipe(chip, pipe, 0);
if (err < 0)
return err;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0)
err = vx_toggle_pipe(chip, pipe, 1);
if (err < 0)
return err;
break;
default:
@ -792,13 +798,15 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs)
snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode);
vx_init_rmh(&rmh, CMD_FREE_PIPE);
vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0);
if ((err = vx_send_msg(chip, &rmh)) < 0)
err = vx_send_msg(chip, &rmh);
if (err < 0)
return err;
vx_init_rmh(&rmh, CMD_RES_PIPE);
vx_set_pipe_cmd_params(&rmh, 0, pipe->number, pipe->channels);
if (data_mode)
rmh.Cmd[0] |= BIT_DATA_MODE;
if ((err = vx_send_msg(chip, &rmh)) < 0)
err = vx_send_msg(chip, &rmh);
if (err < 0)
return err;
pipe->data_mode = data_mode;
}
@ -810,7 +818,8 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs)
}
vx_set_clock(chip, runtime->rate);
if ((err = vx_set_format(chip, pipe, runtime)) < 0)
err = vx_set_format(chip, pipe, runtime);
if (err < 0)
return err;
if (vx_is_pcmcia(chip)) {
@ -1187,7 +1196,8 @@ int snd_vx_pcm_new(struct vx_core *chip)
unsigned int i;
int err;
if ((err = vx_init_audio_io(chip)) < 0)
err = vx_init_audio_io(chip);
if (err < 0)
return err;
for (i = 0; i < chip->hw->num_codecs; i++) {

View File

@ -18,8 +18,25 @@ config SND_DICE
select SND_HWDEP
select SND_FIREWIRE_LIB
help
Say Y here to include support for many DACs based on the DICE
chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces.
Say Y here to include support for devices based on the DICE chip family
(DICE-II/TCD2210(Mini)/TCD2220(Jr.)) which TC Applied Technologies (TCAT) produced.
* Allen and Heath Zed R16
* Alesis iO 14/26 FireWire, MasterControl, MultiMix 8/12/16 FireWire
* Avid Mbox 3 Pro
* FlexRadio Systems FLEX-3000, FLEX-5000
* Focusrite Liquid Saffire 56
* Focusrite Saffire Pro 14, Pro 24, Pro 24 DSP, Pro 26, Pro 40(TCD2220)
* Harman Music Group Lexicon I-ONIX FW810S
* Loud Technologies Mackie Onyx Blackbird, Onyx 820i/1220i/1620i/1640i (latter models)
* M-Audio ProFire 610/2626
* Mytek Stereo192-DSD DAC
* Midas Klark Teknik VeniceF series
* PreSonus FireStudio, FireStudio Mobile, FireStudio Project, FireStudio Tube
* PreSonus StudioLive 16.4.2, 16.0.2, 24.4.2, 32.4.2
* Solid State Logic Duende Classic, Duende Mini
* TC Electronic Studio Konnekt 48, Konnekt 24D, Konnekt Live, Impact Twin
* TC Electronic Digital Konnekt x32, Desktop Konnekt 6
* Weiss Engineering ADC2, Vesta, Minerva, AFI1, DAC1, INT202, DAC202
To compile this driver as a module, choose M here: the module
will be called snd-dice.
@ -38,7 +55,7 @@ config SND_OXFW
* Mackie(Loud) Onyx 1640i (former model)
* Mackie(Loud) Onyx Satellite
* Mackie(Loud) Tapco Link.Firewire
* Mackie(Loud) d.4 pro
* Mackie(Loud) d.2 pro/d.4 pro (built-in FireWire card with OXFW971 ASIC)
* Mackie(Loud) U.420/U.420d
* TASCAM FireOne
* Stanton Controllers & Systems 1 Deck/Mixer
@ -84,7 +101,7 @@ config SND_BEBOB
* PreSonus FIREBOX/FIREPOD/FP10/Inspire1394
* BridgeCo RDAudio1/Audio5
* Mackie Onyx 1220/1620/1640 (FireWire I/O Card)
* Mackie d.2 (FireWire Option) and d.2 Pro
* Mackie d.2 (optional FireWire card with DM1000 ASIC)
* Stanton FinalScratch 2 (ScratchAmp)
* Tascam IF-FW/DM
* Behringer XENIX UFX 1204/1604
@ -110,6 +127,7 @@ config SND_BEBOB
* M-Audio Ozonic/NRV10/ProfireLightBridge
* M-Audio FireWire 1814/ProjectMix IO
* Digidesign Mbox 2 Pro
* ToneWeal FW66
To compile this driver as a module, choose M here: the module
will be called snd-bebob.
@ -148,12 +166,16 @@ config SND_FIREWIRE_MOTU
select SND_HWDEP
help
Say Y here to enable support for FireWire devices which MOTU produced:
* 828
* 896
* 828mk2
* Traveler
* Ultralite
* 8pre
* 828mk3 (FireWire only)
* 828mk3 (Hybrid)
* Ultralite mk3 (FireWire only)
* Ultralite mk3 (Hybrid)
* Audio Express
* 4pre

View File

@ -410,10 +410,10 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
* @s: the AMDTP stream to initialize
* @unit: the target of the stream
* @dir: the direction of stream
* @flags: the packet transmission method to use
* @flags: the details of the streaming protocol consist of cip_flags enumeration-constants.
*/
int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags)
enum amdtp_stream_direction dir, unsigned int flags)
{
amdtp_stream_process_ctx_payloads_t process_ctx_payloads;

View File

@ -45,5 +45,5 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
struct snd_rawmidi_substream *midi);
int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags);
enum amdtp_stream_direction dir, unsigned int flags);
#endif

View File

@ -49,7 +49,7 @@ TRACE_EVENT(amdtp_packet,
__entry->data_blocks = data_blocks;
__entry->data_block_counter = data_block_counter,
__entry->packet_index = packet_index;
__entry->irq = !!in_interrupt();
__entry->irq = !!in_softirq();
__entry->index = index;
),
TP_printk(

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,8 @@
* @CIP_NO_HEADERS: a lack of headers in packets
* @CIP_UNALIGHED_DBC: Only for in-stream. The value of dbc is not alighed to
* the value of current SYT_INTERVAL; e.g. initial value is not zero.
* @CIP_UNAWARE_SYT: For outgoing packet, the value in SYT field of CIP is 0xffff.
* For incoming packet, the value in SYT field of CIP is not handled.
*/
enum cip_flags {
CIP_NONBLOCKING = 0x00,
@ -48,6 +50,7 @@ enum cip_flags {
CIP_HEADER_WITHOUT_EOH = 0x80,
CIP_NO_HEADER = 0x100,
CIP_UNALIGHED_DBC = 0x200,
CIP_UNAWARE_SYT = 0x400,
};
/**
@ -112,7 +115,8 @@ typedef unsigned int (*amdtp_stream_process_ctx_payloads_t)(
struct amdtp_domain;
struct amdtp_stream {
struct fw_unit *unit;
enum cip_flags flags;
// The combination of cip_flags enumeration-constants.
unsigned int flags;
enum amdtp_stream_direction direction;
struct mutex mutex;
@ -134,19 +138,37 @@ struct amdtp_stream {
// Fixed interval of dbc between previos/current
// packets.
unsigned int dbc_interval;
// The device starts multiplexing events to the packet.
bool event_starts;
struct {
struct seq_desc *descs;
unsigned int size;
unsigned int tail;
} cache;
} tx;
struct {
// To calculate CIP data blocks and tstamp.
unsigned int transfer_delay;
unsigned int seq_index;
// To generate CIP header.
unsigned int fdf;
int syt_override;
// To generate constant hardware IRQ.
unsigned int event_count;
unsigned int events_per_period;
// To calculate CIP data blocks and tstamp.
struct {
struct seq_desc *descs;
unsigned int size;
unsigned int tail;
unsigned int head;
} seq;
unsigned int data_block_state;
unsigned int syt_offset_state;
unsigned int last_syt_offset;
struct amdtp_stream *replay_target;
unsigned int cache_head;
} rx;
} ctx_data;
@ -157,20 +179,21 @@ struct amdtp_stream {
unsigned int sph;
unsigned int fmt;
/* Internal flags. */
// Internal flags.
unsigned int transfer_delay;
enum cip_sfc sfc;
unsigned int syt_interval;
/* For a PCM substream processing. */
struct snd_pcm_substream *pcm;
struct work_struct period_work;
snd_pcm_uframes_t pcm_buffer_pointer;
unsigned int pcm_period_pointer;
/* To wait for first packet. */
bool callbacked;
wait_queue_head_t callback_wait;
u32 start_cycle;
// To start processing content of packets at the same cycle in several contexts for
// each direction.
bool ready_processing;
wait_queue_head_t ready_wait;
unsigned int next_cycle;
/* For backends to process data blocks. */
void *protocol;
@ -184,7 +207,7 @@ struct amdtp_stream {
};
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags,
enum amdtp_stream_direction dir, unsigned int flags,
unsigned int fmt,
amdtp_stream_process_ctx_payloads_t process_ctx_payloads,
unsigned int protocol_size);
@ -259,21 +282,6 @@ static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
return sfc & 1;
}
/**
* amdtp_stream_wait_callback - sleep till callbacked or timeout
* @s: the AMDTP stream
* @timeout: msec till timeout
*
* If this function return false, the AMDTP stream should be stopped.
*/
static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
unsigned int timeout)
{
return wait_event_timeout(s->callback_wait,
s->callbacked,
msecs_to_jiffies(timeout)) > 0;
}
struct seq_desc {
unsigned int syt_offset;
unsigned int data_blocks;
@ -287,13 +295,16 @@ struct amdtp_domain {
struct amdtp_stream *irq_target;
struct seq_desc *seq_descs;
unsigned int seq_size;
unsigned int seq_tail;
struct {
unsigned int tx_init_skip;
unsigned int tx_start;
unsigned int rx_start;
} processing_cycle;
unsigned int data_block_state;
unsigned int syt_offset_state;
unsigned int last_syt_offset;
struct {
bool enable:1;
bool on_the_fly:1;
} replay;
};
int amdtp_domain_init(struct amdtp_domain *d);
@ -302,7 +313,8 @@ void amdtp_domain_destroy(struct amdtp_domain *d);
int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
int channel, int speed);
int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle);
int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq,
bool replay_on_the_fly);
void amdtp_domain_stop(struct amdtp_domain *d);
static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
@ -319,4 +331,25 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
struct amdtp_stream *s);
int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s);
/**
* amdtp_domain_wait_ready - sleep till being ready to process packets or timeout
* @d: the AMDTP domain
* @timeout_ms: msec till timeout
*
* If this function return false, the AMDTP domain should be stopped.
*/
static inline bool amdtp_domain_wait_ready(struct amdtp_domain *d, unsigned int timeout_ms)
{
struct amdtp_stream *s;
list_for_each_entry(s, &d->streams, list) {
unsigned int j = msecs_to_jiffies(timeout_ms);
if (wait_event_interruptible_timeout(s->ready_wait, s->ready_processing, j) <= 0)
return false;
}
return true;
}
#endif

View File

@ -40,14 +40,12 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
#define VEN_EDIROL 0x000040ab
#define VEN_PRESONUS 0x00000a92
#define VEN_BRIDGECO 0x000007f5
#define VEN_MACKIE1 0x0000000f
#define VEN_MACKIE2 0x00000ff2
#define VEN_MACKIE 0x00000ff2
#define VEN_STANTON 0x00001260
#define VEN_TASCAM 0x0000022e
#define VEN_BEHRINGER 0x00001564
#define VEN_APOGEE 0x000003db
#define VEN_ESI 0x00000f1b
#define VEN_ACOUSTIC 0x00000002
#define VEN_CME 0x0000000a
#define VEN_PHONIC 0x00001496
#define VEN_LYNX 0x000019e5
@ -56,14 +54,15 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
#define VEN_TERRATEC 0x00000aac
#define VEN_YAMAHA 0x0000a0de
#define VEN_FOCUSRITE 0x0000130e
#define VEN_MAUDIO1 0x00000d6c
#define VEN_MAUDIO2 0x000007f5
#define VEN_MAUDIO 0x00000d6c
#define VEN_DIGIDESIGN 0x00a07e
#define OUI_SHOUYO 0x002327
#define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000
#define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060
#define MODEL_MAUDIO_FW1814 0x00010071
#define MODEL_MAUDIO_PROJECTMIX 0x00010091
#define MODEL_MAUDIO_PROFIRELIGHTBRIDGE 0x000100a1
static int
name_device(struct snd_bebob *bebob)
@ -74,7 +73,6 @@ name_device(struct snd_bebob *bebob)
u32 hw_id;
u32 data[2] = {0};
u32 revision;
u32 version;
int err;
/* get vendor name from root directory */
@ -107,12 +105,6 @@ name_device(struct snd_bebob *bebob)
if (err < 0)
goto end;
err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_BEBOB_VERSION,
&version);
if (err < 0)
goto end;
bebob->version = version;
strcpy(bebob->card->driver, "BeBoB");
strcpy(bebob->card->shortname, model);
strcpy(bebob->card->mixername, model);
@ -135,6 +127,9 @@ bebob_card_free(struct snd_card *card)
mutex_unlock(&devices_mutex);
snd_bebob_stream_destroy_duplex(bebob);
mutex_destroy(&bebob->mutex);
fw_unit_put(bebob->unit);
}
static const struct snd_bebob_spec *
@ -162,16 +157,55 @@ check_audiophile_booted(struct fw_unit *unit)
return strncmp(name, "FW Audiophile Bootloader", 24) != 0;
}
static void
do_registration(struct work_struct *work)
static int detect_quirks(struct snd_bebob *bebob, const struct ieee1394_device_id *entry)
{
if (entry->vendor_id == VEN_MAUDIO) {
switch (entry->model_id) {
case MODEL_MAUDIO_PROFIRELIGHTBRIDGE:
// M-Audio ProFire Lightbridge has a quirk to transfer packets with
// discontinuous cycle or data block counter in early stage of packet
// streaming. The cycle span from the first packet with event is variable.
bebob->quirks |= SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC;
break;
case MODEL_MAUDIO_FW1814:
case MODEL_MAUDIO_PROJECTMIX:
// At high sampling rate, M-Audio special firmware transmits empty packet
// with the value of dbc incremented by 8.
bebob->quirks |= SND_BEBOB_QUIRK_WRONG_DBC;
break;
default:
break;
}
}
return 0;
}
static int bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_bebob *bebob =
container_of(work, struct snd_bebob, dwork.work);
unsigned int card_index;
struct snd_card *card;
struct snd_bebob *bebob;
const struct snd_bebob_spec *spec;
int err;
if (bebob->registered)
return;
if (entry->vendor_id == VEN_FOCUSRITE &&
entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)
spec = get_saffire_spec(unit);
else if (entry->vendor_id == VEN_MAUDIO &&
entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH &&
!check_audiophile_booted(unit))
spec = NULL;
else
spec = (const struct snd_bebob_spec *)entry->driver_data;
if (spec == NULL) {
// To boot up M-Audio models.
if (entry->vendor_id == VEN_MAUDIO || entry->vendor_id == VEN_BRIDGECO)
return snd_bebob_maudio_load_firmware(unit);
else
return -ENODEV;
}
mutex_lock(&devices_mutex);
for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
@ -180,27 +214,40 @@ do_registration(struct work_struct *work)
}
if (card_index >= SNDRV_CARDS) {
mutex_unlock(&devices_mutex);
return;
return -ENOENT;
}
err = snd_card_new(&bebob->unit->device, index[card_index],
id[card_index], THIS_MODULE, 0, &bebob->card);
err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
sizeof(*bebob), &card);
if (err < 0) {
mutex_unlock(&devices_mutex);
return;
return err;
}
card->private_free = bebob_card_free;
set_bit(card_index, devices_used);
mutex_unlock(&devices_mutex);
bebob->card->private_free = bebob_card_free;
bebob->card->private_data = bebob;
bebob = card->private_data;
bebob->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, bebob);
bebob->card = card;
bebob->card_index = card_index;
bebob->spec = spec;
mutex_init(&bebob->mutex);
spin_lock_init(&bebob->lock);
init_waitqueue_head(&bebob->hwdep_wait);
err = name_device(bebob);
if (err < 0)
goto error;
err = detect_quirks(bebob, entry);
if (err < 0)
goto error;
if (bebob->spec == &maudio_special_spec) {
if (bebob->entry->model_id == MODEL_MAUDIO_FW1814)
if (entry->model_id == MODEL_MAUDIO_FW1814)
err = snd_bebob_maudio_special_discover(bebob, true);
else
err = snd_bebob_maudio_special_discover(bebob, false);
@ -230,80 +277,26 @@ do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(bebob->card);
err = snd_card_register(card);
if (err < 0)
goto error;
bebob->registered = true;
return;
error:
snd_card_free(bebob->card);
dev_info(&bebob->unit->device,
"Sound card registration failed: %d\n", err);
}
static int
bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_bebob *bebob;
const struct snd_bebob_spec *spec;
if (entry->vendor_id == VEN_FOCUSRITE &&
entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)
spec = get_saffire_spec(unit);
else if (entry->vendor_id == VEN_MAUDIO1 &&
entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH &&
!check_audiophile_booted(unit))
spec = NULL;
else
spec = (const struct snd_bebob_spec *)entry->driver_data;
if (spec == NULL) {
if (entry->vendor_id == VEN_MAUDIO1 ||
entry->vendor_id == VEN_MAUDIO2)
return snd_bebob_maudio_load_firmware(unit);
else
return -ENODEV;
}
/* Allocate this independent of sound card instance. */
bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob),
GFP_KERNEL);
if (!bebob)
return -ENOMEM;
bebob->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, bebob);
bebob->entry = entry;
bebob->spec = spec;
mutex_init(&bebob->mutex);
spin_lock_init(&bebob->lock);
init_waitqueue_head(&bebob->hwdep_wait);
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&bebob->dwork, do_registration);
if (entry->vendor_id != VEN_MAUDIO1 ||
(entry->model_id != MODEL_MAUDIO_FW1814 &&
entry->model_id != MODEL_MAUDIO_PROJECTMIX)) {
snd_fw_schedule_registration(unit, &bebob->dwork);
} else {
/*
* This is a workaround. This bus reset seems to have an effect
* to make devices correctly handling transactions. Without
* this, the devices have gap_count mismatch. This causes much
* failure of transaction.
*
* Just after registration, user-land application receive
* signals from dbus and starts I/Os. To avoid I/Os till the
* future bus reset, registration is done in next update().
*/
fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card,
false, true);
if (entry->vendor_id == VEN_MAUDIO &&
(entry->model_id == MODEL_MAUDIO_FW1814 || entry->model_id == MODEL_MAUDIO_PROJECTMIX)) {
// This is a workaround. This bus reset seems to have an effect to make devices
// correctly handling transactions. Without this, the devices have gap_count
// mismatch. This causes much failure of transaction.
//
// Just after registration, user-land application receive signals from dbus and
// starts I/Os. To avoid I/Os till the future bus reset, registration is done in
// next update().
fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, false, true);
}
return 0;
error:
snd_card_free(card);
return err;
}
/*
@ -330,11 +323,7 @@ bebob_update(struct fw_unit *unit)
if (bebob == NULL)
return;
/* Postpone a workqueue for deferred registration. */
if (!bebob->registered)
snd_fw_schedule_registration(unit, &bebob->dwork);
else
fcp_bus_reset(bebob->unit);
fcp_bus_reset(bebob->unit);
}
static void bebob_remove(struct fw_unit *unit)
@ -344,20 +333,8 @@ static void bebob_remove(struct fw_unit *unit)
if (bebob == NULL)
return;
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&bebob->dwork);
if (bebob->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(bebob->card);
}
mutex_destroy(&bebob->mutex);
fw_unit_put(bebob->unit);
// Block till all of ALSA character devices are released.
snd_card_free(bebob->card);
}
static const struct snd_bebob_rate_spec normal_rate_spec = {
@ -370,6 +347,22 @@ static const struct snd_bebob_spec spec_normal = {
.meter = NULL
};
#define SPECIFIER_1394TA 0x00a02d
// The immediate entry for version in unit directory differs depending on models:
// * 0x010001
// * 0x014001
#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID | \
IEEE1394_MATCH_SPECIFIER_ID, \
.vendor_id = vendor, \
.model_id = model, \
.specifier_id = SPECIFIER_1394TA, \
.driver_data = (kernel_ulong_t)data \
}
static const struct ieee1394_device_id bebob_id_table[] = {
/* Edirol, FA-66 */
SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010049, &spec_normal),
@ -386,9 +379,9 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* BridgeCo, Audio5 */
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal),
/* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */
SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal),
// Mackie, d.2 (Firewire option card) and d.2 Pro (the card is built-in).
SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal),
SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal),
// Mackie, d.2 (optional Firewire card with DM1000).
SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal),
/* Stanton, ScratchAmp */
SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal),
/* Tascam, IF-FW DM */
@ -410,17 +403,20 @@ static const struct ieee1394_device_id bebob_id_table[] = {
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal),
/* ESI, Quatafire610 */
SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal),
/* AcousticReality, eARMasterOne */
SND_BEBOB_DEV_ENTRY(VEN_ACOUSTIC, 0x00000002, &spec_normal),
// AcousticReality, eARMasterOne. Terratec OEM.
SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal),
/* CME, MatrixKFW */
SND_BEBOB_DEV_ENTRY(VEN_CME, 0x00030000, &spec_normal),
/* Phonic, Helix Board 12 MkII */
// Phonic Helix Board 12 FireWire MkII.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00050000, &spec_normal),
/* Phonic, Helix Board 18 MkII */
// Phonic Helix Board 18 FireWire MkII.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00060000, &spec_normal),
/* Phonic, Helix Board 24 MkII */
// Phonic Helix Board 24 FireWire MkII.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00070000, &spec_normal),
/* Phonic, Helix Board 12 Universal/18 Universal/24 Universal */
// Phonic FireFly 808 FireWire.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00080000, &spec_normal),
// Phonic FireFly 202, 302, 808 Universal.
// Phinic Helix Board 12/18/24 FireWire, 12/18/24 Universal
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00000000, &spec_normal),
/* Lynx, Aurora 8/16 (LT-FW) */
SND_BEBOB_DEV_ENTRY(VEN_LYNX, 0x00000001, &spec_normal),
@ -447,45 +443,35 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* Focusrite, SaffirePro 26 I/O */
SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec),
/* Focusrite, SaffirePro 10 I/O */
{
// The combination of vendor_id and model_id is the same as the
// same as the one of Liquid Saffire 56.
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.vendor_id = VEN_FOCUSRITE,
.model_id = 0x000006,
.specifier_id = 0x00a02d,
.version = 0x010001,
.driver_data = (kernel_ulong_t)&saffirepro_10_spec,
},
SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x000006, &saffirepro_10_spec),
/* Focusrite, Saffire(no label and LE) */
SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH,
&saffire_spec),
/* M-Audio, Firewire 410 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010058, NULL), /* bootloader */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010046, &maudio_fw410_spec),
// M-Audio, Firewire 410. The vendor field is left as BridgeCo. AG.
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010058, NULL),
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010046, &maudio_fw410_spec),
/* M-Audio, Firewire Audiophile */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_AUDIOPHILE_BOTH,
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_AUDIOPHILE_BOTH,
&maudio_audiophile_spec),
/* M-Audio, Firewire Solo */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010062, &maudio_solo_spec),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010062, &maudio_solo_spec),
/* M-Audio, Ozonic */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x0000000a, &maudio_ozonic_spec),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x0000000a, &maudio_ozonic_spec),
/* M-Audio NRV10 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010081, &maudio_nrv10_spec),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010081, &maudio_nrv10_spec),
/* M-Audio, ProFireLightbridge */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROFIRELIGHTBRIDGE, &spec_normal),
/* Firewire 1814 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010070, NULL), /* bootloader */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_FW1814,
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010070, NULL), /* bootloader */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_FW1814,
&maudio_special_spec),
/* M-Audio ProjectMix */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_PROJECTMIX,
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROJECTMIX,
&maudio_special_spec),
/* Digidesign Mbox 2 Pro */
SND_BEBOB_DEV_ENTRY(VEN_DIGIDESIGN, 0x0000a9, &spec_normal),
// Toneweal FW66.
SND_BEBOB_DEV_ENTRY(OUI_SHOUYO, 0x020002, &spec_normal),
/* IDs are unknown but able to be supported */
/* Apogee, Mini-ME Firewire */
/* Apogee, Mini-DAC Firewire */
@ -496,11 +482,6 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* Infrasonic, Windy6 */
/* Mackie, Digital X Bus x.200 */
/* Mackie, Digital X Bus x.400 */
/* Phonic, HB 12 */
/* Phonic, HB 24 */
/* Phonic, HB 18 */
/* Phonic, FireFly 202 */
/* Phonic, FireFly 302 */
/* Rolf Spuler, Firewire Guitar */
{}
};

View File

@ -75,6 +75,11 @@ struct snd_bebob_spec {
const struct snd_bebob_meter_spec *meter;
};
enum snd_bebob_quirk {
SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC = (1 << 0),
SND_BEBOB_QUIRK_WRONG_DBC = (1 << 1),
};
struct snd_bebob {
struct snd_card *card;
struct fw_unit *unit;
@ -83,11 +88,8 @@ struct snd_bebob {
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
const struct ieee1394_device_id *entry;
const struct snd_bebob_spec *spec;
unsigned int quirks; // Combination of snd_bebob_quirk enumerations.
unsigned int midi_input_ports;
unsigned int midi_output_ports;
@ -113,9 +115,6 @@ struct snd_bebob {
/* for M-Audio special devices */
void *maudio_special_quirk;
/* For BeBoB version quirk. */
unsigned int version;
struct amdtp_domain domain;
};
@ -254,13 +253,4 @@ extern const struct snd_bebob_spec maudio_special_spec;
int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
int snd_bebob_maudio_load_firmware(struct fw_unit *unit);
#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID, \
.vendor_id = vendor, \
.model_id = model, \
.driver_data = (kernel_ulong_t)data \
}
#endif

View File

@ -7,8 +7,7 @@
#include "./bebob.h"
#define CALLBACK_TIMEOUT 2500
#define FW_ISO_RESOURCE_DELAY 1000
#define READY_TIMEOUT_MS 4000
/*
* NOTE;
@ -402,12 +401,6 @@ static void break_both_connections(struct snd_bebob *bebob)
{
cmp_connection_break(&bebob->in_conn);
cmp_connection_break(&bebob->out_conn);
// These models seem to be in transition state for a longer time. When
// accessing in the state, any transactions is corrupted. In the worst
// case, the device is going to reboot.
if (bebob->version < 2)
msleep(600);
}
static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
@ -437,6 +430,7 @@ static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
{
unsigned int flags = CIP_BLOCKING;
enum amdtp_stream_direction dir_stream;
struct cmp_connection *conn;
enum cmp_direction dir_conn;
@ -452,32 +446,21 @@ static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
dir_conn = CMP_INPUT;
}
if (stream == &bebob->tx_stream) {
if (bebob->quirks & SND_BEBOB_QUIRK_WRONG_DBC)
flags |= CIP_EMPTY_HAS_WRONG_DBC;
}
err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
if (err < 0)
return err;
err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING);
err = amdtp_am824_init(stream, bebob->unit, dir_stream, flags);
if (err < 0) {
cmp_connection_destroy(conn);
return err;
}
if (stream == &bebob->tx_stream) {
// BeBoB v3 transfers packets with these qurks:
// - In the beginning of streaming, the value of dbc is
// incremented even if no data blocks are transferred.
// - The value of dbc is reset suddenly.
if (bebob->version > 2)
bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
CIP_SKIP_DBC_ZERO_CHECK;
// At high sampling rate, M-Audio special firmware transmits
// empty packet with the value of dbc incremented by 8 but the
// others are valid to IEC 61883-1.
if (bebob->maudio_special_quirk)
bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
}
return 0;
}
@ -624,9 +607,8 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
if (!amdtp_stream_running(&bebob->rx_stream)) {
enum snd_bebob_clock_type src;
struct amdtp_stream *master, *slave;
unsigned int curr_rate;
unsigned int ir_delay_cycle;
unsigned int tx_init_skip_cycles;
if (bebob->maudio_special_quirk) {
err = bebob->spec->rate->get(bebob, &curr_rate);
@ -638,36 +620,28 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
if (err < 0)
return err;
if (src != SND_BEBOB_CLOCK_TYPE_SYT) {
master = &bebob->tx_stream;
slave = &bebob->rx_stream;
} else {
master = &bebob->rx_stream;
slave = &bebob->tx_stream;
}
err = start_stream(bebob, master);
err = start_stream(bebob, &bebob->rx_stream);
if (err < 0)
goto error;
err = start_stream(bebob, slave);
err = start_stream(bebob, &bebob->tx_stream);
if (err < 0)
goto error;
// The device postpones start of transmission mostly for 1 sec
// after receives packets firstly. For safe, IR context starts
// 0.4 sec (=3200 cycles) later to version 1 or 2 firmware,
// 2.0 sec (=16000 cycles) for version 3 firmware. This is
// within 2.5 sec (=CALLBACK_TIMEOUT).
// Furthermore, some devices transfer isoc packets with
// discontinuous counter in the beginning of packet streaming.
// The delay has an effect to avoid detection of this
// discontinuity.
if (bebob->version < 2)
ir_delay_cycle = 3200;
if (!(bebob->quirks & SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC))
tx_init_skip_cycles = 0;
else
ir_delay_cycle = 16000;
err = amdtp_domain_start(&bebob->domain, ir_delay_cycle);
tx_init_skip_cycles = 16000;
// MEMO: Some devices start packet transmission long enough after establishment of
// CMP connection. In the early stage of packet streaming, any device transfers
// NODATA packets. After several hundred cycles, it begins to multiplex event into
// the packet with adequate value of syt field in CIP header. Some devices are
// strictly to generate any discontinuity in the sequence of tx packet when they
// receives inadequate sequence of value in syt field of CIP header. In the case,
// the request to break CMP connection is often corrupted, then any transaction
// results in unrecoverable error, sometimes generate bus-reset.
err = amdtp_domain_start(&bebob->domain, tx_init_skip_cycles, true, false);
if (err < 0)
goto error;
@ -684,10 +658,9 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
}
}
if (!amdtp_stream_wait_callback(&bebob->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&bebob->tx_stream,
CALLBACK_TIMEOUT)) {
// Some devices postpone start of transmission mostly for 1 sec after receives
// packets firstly.
if (!amdtp_domain_wait_ready(&bebob->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
@ -883,6 +856,11 @@ static int detect_midi_ports(struct snd_bebob *bebob,
err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count);
if (err < 0)
break;
// Yamaha GO44, GO46, Terratec Phase 24, Phase x24 reports 0 for the number of
// channels in external output plug 3 (MIDI type) even if it has a pair of physical
// MIDI jacks. As a workaround, assume it as one.
if (ch_count == 0)
ch_count = 1;
*midi_ports += ch_count;
}
@ -961,12 +939,12 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob)
if (err < 0)
goto end;
err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN,
err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN,
plugs[2], &bebob->midi_input_ports);
if (err < 0)
goto end;
err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT,
err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT,
plugs[3], &bebob->midi_output_ports);
if (err < 0)
goto end;

View File

@ -8,8 +8,8 @@
#include "dice.h"
#define CALLBACK_TIMEOUT 200
#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC)
#define READY_TIMEOUT_MS 200
#define NOTIFICATION_TIMEOUT_MS 100
struct reg_params {
unsigned int count;
@ -57,13 +57,9 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
return -EINVAL;
}
/*
* This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE
* to GLOBAL_STATUS. Especially, just after powering on, these are different.
*/
static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate)
static int select_clock(struct snd_dice *dice, unsigned int rate)
{
__be32 reg, nominal;
__be32 reg;
u32 data;
int i;
int err;
@ -94,19 +90,8 @@ static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate)
return err;
if (wait_for_completion_timeout(&dice->clock_accepted,
msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
/*
* Old versions of Dice firmware transfer no notification when
* the same clock status as current one is set. In this case,
* just check current clock status.
*/
err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS,
&nominal, sizeof(nominal));
if (err < 0)
return err;
if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED))
return -ETIMEDOUT;
}
msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
return -ETIMEDOUT;
return 0;
}
@ -304,7 +289,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
// Just after owning the unit (GLOBAL_OWNER), the unit can
// return invalid stream formats. Selecting clock parameters
// have an effect for the unit to refine it.
err = ensure_phase_lock(dice, rate);
err = select_clock(dice, rate);
if (err < 0)
return err;
@ -459,20 +444,17 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
goto error;
}
err = amdtp_domain_start(&dice->domain, 0);
// MEMO: The device immediately starts packet transmission when enabled. Some
// devices are strictly to generate any discontinuity in the sequence of tx packet
// when they receives invalid sequence of presentation time in CIP header. The
// sequence replay for media clock recovery can suppress the behaviour.
err = amdtp_domain_start(&dice->domain, 0, true, false);
if (err < 0)
goto error;
for (i = 0; i < MAX_STREAMS; i++) {
if ((i < tx_params.count &&
!amdtp_stream_wait_callback(&dice->tx_stream[i],
CALLBACK_TIMEOUT)) ||
(i < rx_params.count &&
!amdtp_stream_wait_callback(&dice->rx_stream[i],
CALLBACK_TIMEOUT))) {
err = -ETIMEDOUT;
goto error;
}
if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
}
@ -653,7 +635,7 @@ int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
* invalid stream formats. Selecting clock parameters have an effect
* for the unit to refine it.
*/
err = ensure_phase_lock(dice, rate);
err = select_clock(dice, rate);
if (err < 0)
return err;

View File

@ -155,7 +155,7 @@ static void dice_notification(struct fw_card *card, struct fw_request *request,
fw_send_response(card, request, RCODE_COMPLETE);
if (bits & NOTIFY_LOCK_CHG)
if (bits & NOTIFY_CLOCK_ACCEPTED)
complete(&dice->clock_accepted);
wake_up(&dice->hwdep_wait);
}

View File

@ -135,22 +135,51 @@ static void dice_card_free(struct snd_card *card)
snd_dice_stream_destroy_duplex(dice);
snd_dice_transaction_destroy(dice);
mutex_destroy(&dice->mutex);
fw_unit_put(dice->unit);
}
static void do_registration(struct work_struct *work)
static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work);
struct snd_card *card;
struct snd_dice *dice;
snd_dice_detect_formats_t detect_formats;
int err;
if (dice->registered)
return;
if (!entry->driver_data && entry->vendor_id != OUI_SSL) {
err = check_dice_category(unit);
if (err < 0)
return -ENODEV;
}
err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0,
&dice->card);
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dice), &card);
if (err < 0)
return;
dice->card->private_free = dice_card_free;
dice->card->private_data = dice;
return err;
card->private_free = dice_card_free;
dice = card->private_data;
dice->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, dice);
dice->card = card;
if (!entry->driver_data)
detect_formats = snd_dice_stream_detect_current_formats;
else
detect_formats = (snd_dice_detect_formats_t)entry->driver_data;
// Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer
// frequency.
// * Avid M-Box 3 Pro
// * M-Audio Profire 610
// * M-Audio Profire 2626
if (entry->vendor_id == OUI_MAUDIO || entry->vendor_id == OUI_AVID)
dice->disable_double_pcm_frames = true;
spin_lock_init(&dice->lock);
mutex_init(&dice->mutex);
init_completion(&dice->clock_accepted);
init_waitqueue_head(&dice->hwdep_wait);
err = snd_dice_transaction_init(dice);
if (err < 0)
@ -162,7 +191,7 @@ static void do_registration(struct work_struct *work)
dice_card_strings(dice);
err = dice->detect_formats(dice);
err = detect_formats(dice);
if (err < 0)
goto error;
@ -184,105 +213,34 @@ static void do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(dice->card);
err = snd_card_register(card);
if (err < 0)
goto error;
dice->registered = true;
return;
error:
snd_card_free(dice->card);
dev_info(&dice->unit->device,
"Sound card registration failed: %d\n", err);
}
static int dice_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
{
struct snd_dice *dice;
int err;
if (!entry->driver_data && entry->vendor_id != OUI_SSL) {
err = check_dice_category(unit);
if (err < 0)
return -ENODEV;
}
/* Allocate this independent of sound card instance. */
dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL);
if (!dice)
return -ENOMEM;
dice->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, dice);
if (!entry->driver_data) {
dice->detect_formats = snd_dice_stream_detect_current_formats;
} else {
dice->detect_formats =
(snd_dice_detect_formats_t)entry->driver_data;
}
// Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer
// frequency.
// * Avid M-Box 3 Pro
// * M-Audio Profire 610
// * M-Audio Profire 2626
if (entry->vendor_id == OUI_MAUDIO || entry->vendor_id == OUI_AVID)
dice->disable_double_pcm_frames = true;
spin_lock_init(&dice->lock);
mutex_init(&dice->mutex);
init_completion(&dice->clock_accepted);
init_waitqueue_head(&dice->hwdep_wait);
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&dice->dwork, do_registration);
snd_fw_schedule_registration(unit, &dice->dwork);
return 0;
error:
snd_card_free(card);
return err;
}
static void dice_remove(struct fw_unit *unit)
{
struct snd_dice *dice = dev_get_drvdata(&unit->device);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&dice->dwork);
if (dice->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(dice->card);
}
mutex_destroy(&dice->mutex);
fw_unit_put(dice->unit);
// Block till all of ALSA character devices are released.
snd_card_free(dice->card);
}
static void dice_bus_reset(struct fw_unit *unit)
{
struct snd_dice *dice = dev_get_drvdata(&unit->device);
/* Postpone a workqueue for deferred registration. */
if (!dice->registered)
snd_fw_schedule_registration(unit, &dice->dwork);
/* The handler address register becomes initialized. */
snd_dice_transaction_reinit(dice);
/*
* After registration, userspace can start packet streaming, then this
* code block works fine.
*/
if (dice->registered) {
mutex_lock(&dice->mutex);
snd_dice_stream_update_duplex(dice);
mutex_unlock(&dice->mutex);
}
mutex_lock(&dice->mutex);
snd_dice_stream_update_duplex(dice);
mutex_unlock(&dice->mutex);
}
#define DICE_INTERFACE 0x000001

View File

@ -78,9 +78,6 @@ struct snd_dice {
spinlock_t lock;
struct mutex mutex;
bool registered;
struct delayed_work dwork;
/* Offsets for sub-addresses */
unsigned int global_offset;
unsigned int rx_offset;
@ -93,7 +90,6 @@ struct snd_dice {
unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
unsigned int tx_midi_ports[MAX_STREAMS];
unsigned int rx_midi_ports[MAX_STREAMS];
snd_dice_detect_formats_t detect_formats;
struct fw_address_handler notification_handler;
int owner_generation;

View File

@ -396,16 +396,13 @@ int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir)
{
amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
enum cip_flags flags;
unsigned int flags = CIP_NONBLOCKING | CIP_UNAWARE_SYT;
// Use different mode between incoming/outgoing.
if (dir == AMDTP_IN_STREAM) {
flags = CIP_NONBLOCKING;
if (dir == AMDTP_IN_STREAM)
process_ctx_payloads = process_ir_ctx_payloads;
} else {
flags = CIP_BLOCKING;
else
process_ctx_payloads = process_it_ctx_payloads;
}
return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
process_ctx_payloads, sizeof(struct amdtp_dot));

View File

@ -7,7 +7,7 @@
#include "digi00x.h"
#define CALLBACK_TIMEOUT 500
#define READY_TIMEOUT_MS 200
const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
[SND_DG00X_RATE_44100] = 44100,
@ -375,14 +375,15 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
if (err < 0)
goto error;
err = amdtp_domain_start(&dg00x->domain, 0);
// NOTE: The device doesn't start packet transmission till receiving any packet.
// It ignores presentation time expressed by the value of syt field of CIP header
// in received packets. The sequence of the number of data blocks per packet is
// important for media clock recovery.
err = amdtp_domain_start(&dg00x->domain, 0, true, true);
if (err < 0)
goto error;
if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&dg00x->tx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}

View File

@ -47,23 +47,32 @@ static void dg00x_card_free(struct snd_card *card)
snd_dg00x_stream_destroy_duplex(dg00x);
snd_dg00x_transaction_unregister(dg00x);
mutex_destroy(&dg00x->mutex);
fw_unit_put(dg00x->unit);
}
static void do_registration(struct work_struct *work)
static int snd_dg00x_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_dg00x *dg00x =
container_of(work, struct snd_dg00x, dwork.work);
struct snd_card *card;
struct snd_dg00x *dg00x;
int err;
if (dg00x->registered)
return;
err = snd_card_new(&dg00x->unit->device, -1, NULL, THIS_MODULE, 0,
&dg00x->card);
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dg00x), &card);
if (err < 0)
return;
dg00x->card->private_free = dg00x_card_free;
dg00x->card->private_data = dg00x;
return err;
card->private_free = dg00x_card_free;
dg00x = card->private_data;
dg00x->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, dg00x);
dg00x->card = card;
mutex_init(&dg00x->mutex);
spin_lock_init(&dg00x->lock);
init_waitqueue_head(&dg00x->hwdep_wait);
dg00x->is_console = entry->model_id == MODEL_CONSOLE;
err = name_card(dg00x);
if (err < 0)
@ -91,85 +100,33 @@ static void do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(dg00x->card);
err = snd_card_register(card);
if (err < 0)
goto error;
dg00x->registered = true;
return;
error:
snd_card_free(dg00x->card);
dev_info(&dg00x->unit->device,
"Sound card registration failed: %d\n", err);
}
static int snd_dg00x_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
{
struct snd_dg00x *dg00x;
/* Allocate this independent of sound card instance. */
dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x),
GFP_KERNEL);
if (!dg00x)
return -ENOMEM;
dg00x->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, dg00x);
mutex_init(&dg00x->mutex);
spin_lock_init(&dg00x->lock);
init_waitqueue_head(&dg00x->hwdep_wait);
dg00x->is_console = entry->model_id == MODEL_CONSOLE;
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration);
snd_fw_schedule_registration(unit, &dg00x->dwork);
return 0;
error:
snd_card_free(card);
return err;
}
static void snd_dg00x_update(struct fw_unit *unit)
{
struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
/* Postpone a workqueue for deferred registration. */
if (!dg00x->registered)
snd_fw_schedule_registration(unit, &dg00x->dwork);
snd_dg00x_transaction_reregister(dg00x);
/*
* After registration, userspace can start packet streaming, then this
* code block works fine.
*/
if (dg00x->registered) {
mutex_lock(&dg00x->mutex);
snd_dg00x_stream_update_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
}
mutex_lock(&dg00x->mutex);
snd_dg00x_stream_update_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
}
static void snd_dg00x_remove(struct fw_unit *unit)
{
struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&dg00x->dwork);
if (dg00x->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(dg00x->card);
}
mutex_destroy(&dg00x->mutex);
fw_unit_put(dg00x->unit);
// Block till all of ALSA character devices are released.
snd_card_free(dg00x->card);
}
static const struct ieee1394_device_id snd_dg00x_id_table[] = {

View File

@ -37,9 +37,6 @@ struct snd_dg00x {
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
struct amdtp_stream tx_stream;
struct fw_iso_resources tx_resources;

View File

@ -168,6 +168,6 @@ int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
else
process_ctx_payloads = process_it_ctx_payloads;
return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0,
return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0,
process_ctx_payloads, sizeof(struct amdtp_ff));
}

View File

@ -7,7 +7,7 @@
#include "ff.h"
#define CALLBACK_TIMEOUT_MS 200
#define READY_TIMEOUT_MS 200
int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
enum snd_ff_stream_mode *mode)
@ -199,14 +199,15 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
if (err < 0)
goto error;
err = amdtp_domain_start(&ff->domain, 0);
// NOTE: The device doesn't transfer packets unless receiving any packet. The
// sequence of tx packets includes cycle skip corresponding to empty packet or
// NODATA packet in IEC 61883-1/6. The sequence of the number of data blocks per
// packet is important for media clock recovery.
err = amdtp_domain_start(&ff->domain, 0, true, true);
if (err < 0)
goto error;
if (!amdtp_stream_wait_callback(&ff->rx_stream,
CALLBACK_TIMEOUT_MS) ||
!amdtp_stream_wait_callback(&ff->tx_stream,
CALLBACK_TIMEOUT_MS)) {
if (!amdtp_domain_wait_ready(&ff->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}

View File

@ -42,22 +42,33 @@ static void ff_card_free(struct snd_card *card)
snd_ff_stream_destroy_duplex(ff);
snd_ff_transaction_unregister(ff);
mutex_destroy(&ff->mutex);
fw_unit_put(ff->unit);
}
static void do_registration(struct work_struct *work)
static int snd_ff_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_ff *ff = container_of(work, struct snd_ff, dwork.work);
struct snd_card *card;
struct snd_ff *ff;
int err;
if (ff->registered)
return;
err = snd_card_new(&ff->unit->device, -1, NULL, THIS_MODULE, 0,
&ff->card);
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*ff), &card);
if (err < 0)
return;
ff->card->private_free = ff_card_free;
ff->card->private_data = ff;
return err;
card->private_free = ff_card_free;
ff = card->private_data;
ff->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, ff);
ff->card = card;
mutex_init(&ff->mutex);
spin_lock_init(&ff->lock);
init_waitqueue_head(&ff->hwdep_wait);
ff->unit_version = entry->version;
ff->spec = (const struct snd_ff_spec *)entry->driver_data;
err = snd_ff_transaction_register(ff);
if (err < 0)
@ -83,76 +94,31 @@ static void do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(ff->card);
err = snd_card_register(card);
if (err < 0)
goto error;
ff->registered = true;
return;
error:
snd_card_free(ff->card);
dev_info(&ff->unit->device,
"Sound card registration failed: %d\n", err);
}
static int snd_ff_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
{
struct snd_ff *ff;
ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL);
if (!ff)
return -ENOMEM;
ff->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, ff);
mutex_init(&ff->mutex);
spin_lock_init(&ff->lock);
init_waitqueue_head(&ff->hwdep_wait);
ff->unit_version = entry->version;
ff->spec = (const struct snd_ff_spec *)entry->driver_data;
/* Register this sound card later. */
INIT_DEFERRABLE_WORK(&ff->dwork, do_registration);
snd_fw_schedule_registration(unit, &ff->dwork);
return 0;
error:
snd_card_free(card);
return err;
}
static void snd_ff_update(struct fw_unit *unit)
{
struct snd_ff *ff = dev_get_drvdata(&unit->device);
/* Postpone a workqueue for deferred registration. */
if (!ff->registered)
snd_fw_schedule_registration(unit, &ff->dwork);
snd_ff_transaction_reregister(ff);
if (ff->registered)
snd_ff_stream_update_duplex(ff);
snd_ff_stream_update_duplex(ff);
}
static void snd_ff_remove(struct fw_unit *unit)
{
struct snd_ff *ff = dev_get_drvdata(&unit->device);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_work_sync(&ff->dwork.work);
if (ff->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(ff->card);
}
mutex_destroy(&ff->mutex);
fw_unit_put(ff->unit);
// Block till all of ALSA character devices are released.
snd_card_free(ff->card);
}
static const struct snd_ff_spec spec_ff800 = {

View File

@ -69,9 +69,6 @@ struct snd_ff {
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
enum snd_ff_unit_version unit_version;
const struct snd_ff_spec *spec;

View File

@ -194,19 +194,19 @@ efw_card_free(struct snd_card *card)
snd_efw_stream_destroy_duplex(efw);
snd_efw_transaction_remove_instance(efw);
mutex_destroy(&efw->mutex);
fw_unit_put(efw->unit);
}
static void
do_registration(struct work_struct *work)
static int efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_efw *efw = container_of(work, struct snd_efw, dwork.work);
unsigned int card_index;
struct snd_card *card;
struct snd_efw *efw;
int err;
if (efw->registered)
return;
/* check registered cards */
// check registered cards.
mutex_lock(&devices_mutex);
for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
if (!test_bit(card_index, devices_used) && enable[card_index])
@ -214,26 +214,32 @@ do_registration(struct work_struct *work)
}
if (card_index >= SNDRV_CARDS) {
mutex_unlock(&devices_mutex);
return;
return -ENOENT;
}
err = snd_card_new(&efw->unit->device, index[card_index],
id[card_index], THIS_MODULE, 0, &efw->card);
err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
sizeof(*efw), &card);
if (err < 0) {
mutex_unlock(&devices_mutex);
return;
return err;
}
card->private_free = efw_card_free;
set_bit(card_index, devices_used);
mutex_unlock(&devices_mutex);
efw->card->private_free = efw_card_free;
efw->card->private_data = efw;
efw = card->private_data;
efw->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, efw);
efw->card = card;
efw->card_index = card_index;
/* prepare response buffer */
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
efw->resp_buf = devm_kzalloc(&efw->card->card_dev,
snd_efw_resp_buf_size, GFP_KERNEL);
mutex_init(&efw->mutex);
spin_lock_init(&efw->lock);
init_waitqueue_head(&efw->hwdep_wait);
// prepare response buffer.
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
efw->resp_buf = devm_kzalloc(&card->card_dev, snd_efw_resp_buf_size, GFP_KERNEL);
if (!efw->resp_buf) {
err = -ENOMEM;
goto error;
@ -265,80 +271,48 @@ do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(efw->card);
err = snd_card_register(card);
if (err < 0)
goto error;
efw->registered = true;
return;
error:
snd_card_free(efw->card);
dev_info(&efw->unit->device,
"Sound card registration failed: %d\n", err);
}
static int
efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_efw *efw;
efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL);
if (efw == NULL)
return -ENOMEM;
efw->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, efw);
mutex_init(&efw->mutex);
spin_lock_init(&efw->lock);
init_waitqueue_head(&efw->hwdep_wait);
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&efw->dwork, do_registration);
snd_fw_schedule_registration(unit, &efw->dwork);
return 0;
error:
snd_card_free(card);
return err;
}
static void efw_update(struct fw_unit *unit)
{
struct snd_efw *efw = dev_get_drvdata(&unit->device);
/* Postpone a workqueue for deferred registration. */
if (!efw->registered)
snd_fw_schedule_registration(unit, &efw->dwork);
snd_efw_transaction_bus_reset(efw->unit);
/*
* After registration, userspace can start packet streaming, then this
* code block works fine.
*/
if (efw->registered) {
mutex_lock(&efw->mutex);
snd_efw_stream_update_duplex(efw);
mutex_unlock(&efw->mutex);
}
mutex_lock(&efw->mutex);
snd_efw_stream_update_duplex(efw);
mutex_unlock(&efw->mutex);
}
static void efw_remove(struct fw_unit *unit)
{
struct snd_efw *efw = dev_get_drvdata(&unit->device);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&efw->dwork);
// Block till all of ALSA character devices are released.
snd_card_free(efw->card);
}
if (efw->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(efw->card);
}
#define SPECIFIER_1394TA 0x00a02d
#define VERSION_EFW 0x010000
mutex_destroy(&efw->mutex);
fw_unit_put(efw->unit);
#define SND_EFW_DEV_ENTRY(vendor, model) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID | \
IEEE1394_MATCH_SPECIFIER_ID | \
IEEE1394_MATCH_VERSION, \
.vendor_id = vendor,\
.model_id = model, \
.specifier_id = SPECIFIER_1394TA, \
.version = VERSION_EFW, \
}
static const struct ieee1394_device_id efw_id_table[] = {

View File

@ -65,9 +65,6 @@ struct snd_efw {
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
/* for transaction */
u32 seqnum;
bool resp_addr_changable;
@ -181,7 +178,7 @@ struct snd_efw_phys_meters {
} __packed;
enum snd_efw_clock_source {
SND_EFW_CLOCK_SOURCE_INTERNAL = 0,
SND_EFW_CLOCK_SOURCE_SYTMATCH = 1,
// Unused.
SND_EFW_CLOCK_SOURCE_WORDCLOCK = 2,
SND_EFW_CLOCK_SOURCE_SPDIF = 3,
SND_EFW_CLOCK_SOURCE_ADAT_1 = 4,
@ -227,12 +224,4 @@ int snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode);
int snd_efw_create_hwdep_device(struct snd_efw *efw);
#define SND_EFW_DEV_ENTRY(vendor, model) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID, \
.vendor_id = vendor,\
.model_id = model \
}
#endif

View File

@ -6,7 +6,7 @@
*/
#include "./fireworks.h"
#define CALLBACK_TIMEOUT 100
#define READY_TIMEOUT_MS 1000
static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
{
@ -29,7 +29,7 @@ static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
if (err < 0)
return err;
err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING);
err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING | CIP_UNAWARE_SYT);
if (err < 0) {
amdtp_stream_destroy(stream);
cmp_connection_destroy(conn);
@ -264,6 +264,15 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
return err;
if (!amdtp_stream_running(&efw->rx_stream)) {
unsigned int tx_init_skip_cycles;
// Audiofire 2/4 skip an isochronous cycle several thousands after starting
// packet transmission.
if (efw->is_fireworks3 && !efw->is_af9)
tx_init_skip_cycles = 6000;
else
tx_init_skip_cycles = 0;
err = start_stream(efw, &efw->rx_stream, rate);
if (err < 0)
goto error;
@ -272,15 +281,14 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
if (err < 0)
goto error;
err = amdtp_domain_start(&efw->domain, 0);
// NOTE: The device ignores presentation time expressed by the value of syt field
// of CIP header in received packets. The sequence of the number of data blocks per
// packet is important for media clock recovery.
err = amdtp_domain_start(&efw->domain, tx_init_skip_cycles, true, false);
if (err < 0)
goto error;
// Wait first callback.
if (!amdtp_stream_wait_callback(&efw->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&efw->tx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&efw->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}

View File

@ -67,38 +67,6 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode,
}
EXPORT_SYMBOL(snd_fw_transaction);
#define PROBE_DELAY_MS (2 * MSEC_PER_SEC)
/**
* snd_fw_schedule_registration - schedule work for sound card registration
* @unit: an instance for unit on IEEE 1394 bus
* @dwork: delayed work with callback function
*
* This function is not designed for general purposes. When new unit is
* connected to IEEE 1394 bus, the bus is under bus-reset state because of
* topological change. In this state, units tend to fail both of asynchronous
* and isochronous communication. To avoid this problem, this function is used
* to postpone sound card registration after the state. The callers must
* set up instance of delayed work in advance.
*/
void snd_fw_schedule_registration(struct fw_unit *unit,
struct delayed_work *dwork)
{
u64 now, delay;
now = get_jiffies_64();
delay = fw_parent_device(unit)->card->reset_jiffies
+ msecs_to_jiffies(PROBE_DELAY_MS);
if (time_after64(delay, now))
delay -= now;
else
delay = 0;
mod_delayed_work(system_wq, dwork, delay);
}
EXPORT_SYMBOL(snd_fw_schedule_registration);
MODULE_DESCRIPTION("FireWire audio helper functions");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");

View File

@ -23,7 +23,4 @@ static inline bool rcode_is_permanent_error(int rcode)
return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR;
}
void snd_fw_schedule_registration(struct fw_unit *unit,
struct delayed_work *dwork);
#endif

View File

@ -3,5 +3,6 @@ CFLAGS_amdtp-motu.o := -I$(src)
snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
motu-protocol-v2.o motu-protocol-v3.o
motu-protocol-v2.o motu-protocol-v3.o \
motu-protocol-v1.o
obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o

View File

@ -16,6 +16,14 @@
#define CIP_FMT_MOTU_TX_V3 0x22
#define MOTU_FDF_AM824 0x22
#define TICKS_PER_CYCLE 3072
#define CYCLES_PER_SECOND 8000
#define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
#define CIP_SPH_CYCLE_SHIFT 12
#define CIP_SPH_CYCLE_MASK 0x01fff000
#define CIP_SPH_OFFSET_MASK 0x00000fff
/*
* Nominally 3125 bytes/second, but the MIDI port's clock might be
* 1% too slow, and the bus clock 100 ppm too fast.
@ -23,14 +31,6 @@
#define MIDI_BYTES_PER_SECOND 3093
struct amdtp_motu {
/* For timestamp processing. */
unsigned int quotient_ticks_per_event;
unsigned int remainder_ticks_per_event;
unsigned int next_ticks;
unsigned int next_accumulated;
unsigned int next_cycles;
unsigned int next_seconds;
unsigned int pcm_chunks;
unsigned int pcm_byte_offset;
@ -41,26 +41,16 @@ struct amdtp_motu {
int midi_db_count;
unsigned int midi_db_interval;
struct amdtp_motu_cache *cache;
};
int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
unsigned int midi_ports,
struct snd_motu_packet_format *formats)
{
static const struct {
unsigned int quotient_ticks_per_event;
unsigned int remainder_ticks_per_event;
} params[] = {
[CIP_SFC_44100] = { 557, 123 },
[CIP_SFC_48000] = { 512, 0 },
[CIP_SFC_88200] = { 278, 282 },
[CIP_SFC_96000] = { 256, 0 },
[CIP_SFC_176400] = { 139, 141 },
[CIP_SFC_192000] = { 128, 0 },
};
struct amdtp_motu *p = s->protocol;
unsigned int pcm_chunks, data_chunks, data_block_quadlets;
unsigned int delay;
unsigned int mode;
int i, err;
@ -97,19 +87,6 @@ int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
p->midi_db_count = 0;
p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND;
/* IEEE 1394 bus requires. */
delay = 0x2e00;
/* For no-data or empty packets to adjust PCM sampling frequency. */
delay += 8000 * 3072 * s->syt_interval / rate;
p->next_seconds = 0;
p->next_cycles = delay / 3072;
p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event;
p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event;
p->next_ticks = delay % 3072;
p->next_accumulated = 0;
return 0;
}
@ -322,6 +299,34 @@ static void probe_tracepoints_events(struct amdtp_stream *s,
}
}
static void cache_event_offsets(struct amdtp_motu_cache *cache, const __be32 *buf,
unsigned int data_blocks, unsigned int data_block_quadlets)
{
unsigned int *event_offsets = cache->event_offsets;
const unsigned int cache_size = cache->size;
unsigned int cache_tail = cache->tail;
unsigned int base_tick = cache->tx_cycle_count * TICKS_PER_CYCLE;
int i;
for (i = 0; i < data_blocks; ++i) {
u32 sph = be32_to_cpu(*buf);
unsigned int tick;
tick = ((sph & CIP_SPH_CYCLE_MASK) >> CIP_SPH_CYCLE_SHIFT) * TICKS_PER_CYCLE +
(sph & CIP_SPH_OFFSET_MASK);
if (tick < base_tick)
tick += TICKS_PER_SECOND;
event_offsets[cache_tail] = tick - base_tick;
cache_tail = (cache_tail + 1) % cache_size;
buf += data_block_quadlets;
}
cache->tail = cache_tail;
cache->tx_cycle_count = (cache->tx_cycle_count + 1) % CYCLES_PER_SECOND;
}
static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
const struct pkt_desc *descs,
unsigned int packets,
@ -331,12 +336,17 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
unsigned int pcm_frames = 0;
int i;
if (p->cache->tx_cycle_count == UINT_MAX)
p->cache->tx_cycle_count = (s->domain->processing_cycle.tx_start % CYCLES_PER_SECOND);
// For data block processing.
for (i = 0; i < packets; ++i) {
const struct pkt_desc *desc = descs + i;
__be32 *buf = desc->ctx_payload;
unsigned int data_blocks = desc->data_blocks;
cache_event_offsets(p->cache, buf, data_blocks, s->data_block_quadlets);
if (pcm) {
read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
pcm_frames += data_blocks;
@ -354,46 +364,26 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
return pcm_frames;
}
static inline void compute_next_elapse_from_start(struct amdtp_motu *p)
static void write_sph(struct amdtp_motu_cache *cache, __be32 *buffer, unsigned int data_blocks,
unsigned int data_block_quadlets)
{
p->next_accumulated += p->remainder_ticks_per_event;
if (p->next_accumulated >= 441) {
p->next_accumulated -= 441;
p->next_ticks++;
}
p->next_ticks += p->quotient_ticks_per_event;
if (p->next_ticks >= 3072) {
p->next_ticks -= 3072;
p->next_cycles++;
}
if (p->next_cycles >= 8000) {
p->next_cycles -= 8000;
p->next_seconds++;
}
if (p->next_seconds >= 128)
p->next_seconds -= 128;
}
static void write_sph(struct amdtp_stream *s, __be32 *buffer,
unsigned int data_blocks)
{
struct amdtp_motu *p = s->protocol;
unsigned int next_cycles;
unsigned int i;
u32 sph;
unsigned int *event_offsets = cache->event_offsets;
const unsigned int cache_size = cache->size;
unsigned int cache_head = cache->head;
unsigned int base_tick = cache->rx_cycle_count * TICKS_PER_CYCLE;
int i;
for (i = 0; i < data_blocks; i++) {
next_cycles = (s->start_cycle + p->next_cycles) % 8000;
sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff;
unsigned int tick = (base_tick + event_offsets[cache_head]) % TICKS_PER_SECOND;
u32 sph = ((tick / TICKS_PER_CYCLE) << CIP_SPH_CYCLE_SHIFT) | (tick % TICKS_PER_CYCLE);
*buffer = cpu_to_be32(sph);
compute_next_elapse_from_start(p);
buffer += s->data_block_quadlets;
cache_head = (cache_head + 1) % cache_size;
buffer += data_block_quadlets;
}
cache->head = cache_head;
cache->rx_cycle_count = (cache->rx_cycle_count + 1) % CYCLES_PER_SECOND;
}
static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
@ -405,6 +395,9 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
unsigned int pcm_frames = 0;
int i;
if (p->cache->rx_cycle_count == UINT_MAX)
p->cache->rx_cycle_count = (s->domain->processing_cycle.rx_start % CYCLES_PER_SECOND);
// For data block processing.
for (i = 0; i < packets; ++i) {
const struct pkt_desc *desc = descs + i;
@ -423,7 +416,7 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
// TODO: how to interact control messages between userspace?
write_sph(s, buf, data_blocks);
write_sph(p->cache, buf, data_blocks, s->data_block_quadlets);
}
// For tracepoints.
@ -436,11 +429,12 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir,
const struct snd_motu_spec *spec)
const struct snd_motu_spec *spec, struct amdtp_motu_cache *cache)
{
amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
int fmt = CIP_FMT_MOTU;
int flags = CIP_BLOCKING;
unsigned int flags = CIP_BLOCKING | CIP_UNAWARE_SYT;
struct amdtp_motu *p;
int err;
if (dir == AMDTP_IN_STREAM) {
@ -478,9 +472,10 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
if (dir == AMDTP_OUT_STREAM) {
// Use fixed value for FDF field.
s->ctx_data.rx.fdf = MOTU_FDF_AM824;
// Not used.
s->ctx_data.rx.syt_override = 0xffff;
}
p = s->protocol;
p->cache = cache;
return 0;
}

View File

@ -0,0 +1,470 @@
// SPDX-License-Identifier: GPL-2.0-only
// motu-protocol-v1.c - a part of driver for MOTU FireWire series
//
// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
//
// Licensed under the terms of the GNU General Public License, version 2.
#include "motu.h"
#include <linux/delay.h>
// Status register for MOTU 828 (0x'ffff'f000'0b00).
//
// 0xffff0000: ISOC_COMM_CONTROL_MASK in motu-stream.c.
// 0x00008000: mode of optical input interface.
// 0x00008000: for S/PDIF signal.
// 0x00000000: disabled or for ADAT signal.
// 0x00004000: mode of optical output interface.
// 0x00004000: for S/PDIF signal.
// 0x00000000: disabled or for ADAT signal.
// 0x00003f00: monitor input mode.
// 0x00000800: analog-1/2
// 0x00001a00: analog-3/4
// 0x00002c00: analog-5/6
// 0x00003e00: analog-7/8
// 0x00000000: analog-1
// 0x00000900: analog-2
// 0x00001200: analog-3
// 0x00001b00: analog-4
// 0x00002400: analog-5
// 0x00002d00: analog-6
// 0x00003600: analog-7
// 0x00003f00: analog-8
// 0x00000080: enable stream input.
// 0x00000040: disable monitor input.
// 0x00000008: enable main out.
// 0x00000004: rate of sampling clock.
// 0x00000004: 48.0 kHz
// 0x00000000: 44.1 kHz
// 0x00000023: source of sampling clock.
// 0x00000003: source packet header (SPH)
// 0x00000002: S/PDIF on optical/coaxial interface.
// 0x00000021: ADAT on optical interface
// 0x00000001: ADAT on Dsub 9pin
// 0x00000000: internal
#define CLK_828_STATUS_OFFSET 0x0b00
#define CLK_828_STATUS_MASK 0x0000ffff
#define CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF 0x00008000
#define CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF 0x00004000
#define CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES 0x00000080
#define CLK_828_STATUS_FLAG_ENABLE_OUTPUT 0x00000008
#define CLK_828_STATUS_FLAG_RATE_48000 0x00000004
#define CLK_828_STATUS_MASK_SRC 0x00000023
#define CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT 0x00000021
#define CLK_828_STATUS_FLAG_SRC_SPH 0x00000003
#define CLK_828_STATUS_FLAG_SRC_SPDIF 0x00000002
#define CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB 0x00000001
#define CLK_828_STATUS_FLAG_SRC_INTERNAL 0x00000000
// Status register for MOTU 896 (0x'ffff'f000'0b14).
//
// 0xf0000000: enable physical and stream input to DAC.
// 0x80000000: disable
// 0x40000000: disable
// 0x20000000: enable (prior to the other bits)
// 0x10000000: disable
// 0x00000000: disable
// 0x08000000: speed of word clock signal output on BNC interface.
// 0x00000000: force to low rate (44.1/48.0 kHz).
// 0x08000000: follow to system clock.
// 0x04000000: something relevant to clock.
// 0x03000000: enable output.
// 0x02000000: enabled irreversibly once standing unless the device voluntarily disables it.
// 0x01000000: enabled irreversibly once standing unless the device voluntarily disables it.
// 0x00ffff00: monitor input mode.
// 0x00000000: disabled
// 0x00004800: analog-1/2
// 0x00005a00: analog-3/4
// 0x00006c00: analog-5/6
// 0x00007e00: analog-7/8
// 0x00104800: AES/EBU-1/2
// 0x00004000: analog-1
// 0x00004900: analog-2
// 0x00005200: analog-3
// 0x00005b00: analog-4
// 0x00006400: analog-5
// 0x00006d00: analog-6
// 0x00007600: analog-7
// 0x00007f00: analog-8
// 0x00104000: AES/EBU-1
// 0x00104900: AES/EBU-2
// 0x00000060: sample rate conversion for AES/EBU input/output.
// 0x00000000: None
// 0x00000020: input signal is converted to system rate
// 0x00000040: output is slave to input, ignoring system rate
// 0x00000060: output is double rate than system rate
// 0x00000018: nominal rate of sampling clock.
// 0x00000000: 44.1 kHz
// 0x00000008: 48.0 kHz
// 0x00000010: 88.2 kHz
// 0x00000018: 96.0 kHz
// 0x00000007: source of sampling clock.
// 0x00000000: internal
// 0x00000001: ADAT on optical interface
// 0x00000002: AES/EBU on XLR
// 0x00000003: source packet header (SPH)
// 0x00000004: word clock on BNC
// 0x00000005: ADAT on Dsub 9pin
#define CLK_896_STATUS_OFFSET 0x0b14
#define CLK_896_STATUS_FLAG_FETCH_ENABLE 0x20000000
#define CLK_896_STATUS_FLAG_OUTPUT_ON 0x03000000
#define CLK_896_STATUS_MASK_SRC 0x00000007
#define CLK_896_STATUS_FLAG_SRC_INTERNAL 0x00000000
#define CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT 0x00000001
#define CLK_896_STATUS_FLAG_SRC_AESEBU 0x00000002
#define CLK_896_STATUS_FLAG_SRC_SPH 0x00000003
#define CLK_896_STATUS_FLAG_SRC_WORD 0x00000004
#define CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB 0x00000005
#define CLK_896_STATUS_MASK_RATE 0x00000018
#define CLK_896_STATUS_FLAG_RATE_44100 0x00000000
#define CLK_896_STATUS_FLAG_RATE_48000 0x00000008
#define CLK_896_STATUS_FLAG_RATE_88200 0x00000010
#define CLK_896_STATUS_FLAG_RATE_96000 0x00000018
static void parse_clock_rate_828(u32 data, unsigned int *rate)
{
if (data & CLK_828_STATUS_FLAG_RATE_48000)
*rate = 48000;
else
*rate = 44100;
}
static int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate)
{
__be32 reg;
int err;
err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
parse_clock_rate_828(be32_to_cpu(reg), rate);
return 0;
}
static int parse_clock_rate_896(u32 data, unsigned int *rate)
{
switch (data & CLK_896_STATUS_MASK_RATE) {
case CLK_896_STATUS_FLAG_RATE_44100:
*rate = 44100;
break;
case CLK_896_STATUS_FLAG_RATE_48000:
*rate = 48000;
break;
case CLK_896_STATUS_FLAG_RATE_88200:
*rate = 88200;
break;
case CLK_896_STATUS_FLAG_RATE_96000:
*rate = 96000;
break;
default:
return -ENXIO;
}
return 0;
}
static int get_clock_rate_896(struct snd_motu *motu, unsigned int *rate)
{
__be32 reg;
int err;
err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
return parse_clock_rate_896(be32_to_cpu(reg), rate);
}
int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
{
if (motu->spec == &snd_motu_spec_828)
return get_clock_rate_828(motu, rate);
else if (motu->spec == &snd_motu_spec_896)
return get_clock_rate_896(motu, rate);
else
return -ENXIO;
}
static int set_clock_rate_828(struct snd_motu *motu, unsigned int rate)
{
__be32 reg;
u32 data;
int err;
err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
data &= ~CLK_828_STATUS_FLAG_RATE_48000;
if (rate == 48000)
data |= CLK_828_STATUS_FLAG_RATE_48000;
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
}
static int set_clock_rate_896(struct snd_motu *motu, unsigned int rate)
{
unsigned int flag;
__be32 reg;
u32 data;
int err;
err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg);
switch (rate) {
case 44100:
flag = CLK_896_STATUS_FLAG_RATE_44100;
break;
case 48000:
flag = CLK_896_STATUS_FLAG_RATE_48000;
break;
case 88200:
flag = CLK_896_STATUS_FLAG_RATE_88200;
break;
case 96000:
flag = CLK_896_STATUS_FLAG_RATE_96000;
break;
default:
return -EINVAL;
}
data &= ~CLK_896_STATUS_MASK_RATE;
data |= flag;
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
}
int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate)
{
if (motu->spec == &snd_motu_spec_828)
return set_clock_rate_828(motu, rate);
else if (motu->spec == &snd_motu_spec_896)
return set_clock_rate_896(motu, rate);
else
return -ENXIO;
}
static int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_source *src)
{
__be32 reg;
u32 data;
int err;
err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
switch (data & CLK_828_STATUS_MASK_SRC) {
case CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
break;
case CLK_828_STATUS_FLAG_SRC_SPH:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case CLK_828_STATUS_FLAG_SRC_SPDIF:
{
if (data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
else
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
break;
}
case CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
break;
case CLK_828_STATUS_FLAG_SRC_INTERNAL:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
default:
return -ENXIO;
}
return 0;
}
static int get_clock_source_896(struct snd_motu *motu, enum snd_motu_clock_source *src)
{
__be32 reg;
u32 data;
int err;
err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg);
switch (data & CLK_896_STATUS_MASK_SRC) {
case CLK_896_STATUS_FLAG_SRC_INTERNAL:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
break;
case CLK_896_STATUS_FLAG_SRC_AESEBU:
*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
break;
case CLK_896_STATUS_FLAG_SRC_SPH:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case CLK_896_STATUS_FLAG_SRC_WORD:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
case CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
break;
default:
return -ENXIO;
}
return 0;
}
int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src)
{
if (motu->spec == &snd_motu_spec_828)
return get_clock_source_828(motu, src);
else if (motu->spec == &snd_motu_spec_896)
return get_clock_source_896(motu, src);
else
return -ENXIO;
}
static int switch_fetching_mode_828(struct snd_motu *motu, bool enable)
{
__be32 reg;
u32 data;
int err;
err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
data &= ~(CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT);
if (enable) {
// This transaction should be initiated after the device receives batch of packets
// since the device voluntarily mutes outputs. As a workaround, yield processor over
// 100 msec.
msleep(100);
data |= CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT;
}
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
}
static int switch_fetching_mode_896(struct snd_motu *motu, bool enable)
{
__be32 reg;
u32 data;
int err;
err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg);
data &= ~CLK_896_STATUS_FLAG_FETCH_ENABLE;
if (enable)
data |= CLK_896_STATUS_FLAG_FETCH_ENABLE | CLK_896_STATUS_FLAG_OUTPUT_ON;
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, &reg, sizeof(reg));
}
int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable)
{
if (motu->spec == &snd_motu_spec_828)
return switch_fetching_mode_828(motu, enable);
else if (motu->spec == &snd_motu_spec_896)
return switch_fetching_mode_896(motu, enable);
else
return -ENXIO;
}
static int detect_packet_formats_828(struct snd_motu *motu)
{
__be32 reg;
u32 data;
int err;
motu->tx_packet_formats.pcm_byte_offset = 4;
motu->tx_packet_formats.msg_chunks = 2;
motu->rx_packet_formats.pcm_byte_offset = 4;
motu->rx_packet_formats.msg_chunks = 0;
err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
data = be32_to_cpu(reg) & CLK_828_STATUS_MASK;
// The number of chunks is just reduced when SPDIF is activated.
if (!(data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF))
motu->tx_packet_formats.pcm_chunks[0] += 8;
if (!(data & CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF))
motu->rx_packet_formats.pcm_chunks[0] += 8;
return 0;
}
static int detect_packet_formats_896(struct snd_motu *motu)
{
// 24bit PCM frames follow to source packet header without message chunk.
motu->tx_packet_formats.pcm_byte_offset = 4;
motu->rx_packet_formats.pcm_byte_offset = 4;
// No message chunk in data block.
motu->tx_packet_formats.msg_chunks = 0;
motu->rx_packet_formats.msg_chunks = 0;
// Always enable optical interface for ADAT signal since the device have no registers
// to refer to current configuration.
motu->tx_packet_formats.pcm_chunks[0] += 8;
motu->tx_packet_formats.pcm_chunks[1] += 8;
motu->rx_packet_formats.pcm_chunks[0] += 8;
motu->rx_packet_formats.pcm_chunks[1] += 8;
return 0;
}
int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu)
{
memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks,
sizeof(motu->tx_packet_formats.pcm_chunks));
memcpy(motu->rx_packet_formats.pcm_chunks, motu->spec->rx_fixed_pcm_chunks,
sizeof(motu->rx_packet_formats.pcm_chunks));
if (motu->spec == &snd_motu_spec_828)
return detect_packet_formats_828(motu);
else if (motu->spec == &snd_motu_spec_896)
return detect_packet_formats_896(motu);
else
return 0;
}
const struct snd_motu_spec snd_motu_spec_828 = {
.name = "828",
.protocol_version = SND_MOTU_PROTOCOL_V1,
.tx_fixed_pcm_chunks = {10, 0, 0},
.rx_fixed_pcm_chunks = {10, 0, 0},
};
const struct snd_motu_spec snd_motu_spec_896 = {
.name = "896",
.tx_fixed_pcm_chunks = {10, 10, 0},
.rx_fixed_pcm_chunks = {10, 10, 0},
};

View File

@ -12,6 +12,13 @@
#define V2_CLOCK_RATE_SHIFT 3
#define V2_CLOCK_SRC_MASK 0x00000007
#define V2_CLOCK_SRC_SHIFT 0
#define V2_CLOCK_SRC_AESEBU_ON_XLR 0x07
#define V2_CLOCK_SRC_ADAT_ON_DSUB 0x05
#define V2_CLOCK_SRC_WORD_ON_BNC 0x04
#define V2_CLOCK_SRC_SPH 0x03
#define V2_CLOCK_SRC_SPDIF 0x02 // on either coaxial or optical
#define V2_CLOCK_SRC_ADAT_ON_OPT 0x01
#define V2_CLOCK_SRC_INTERNAL 0x00
#define V2_CLOCK_FETCH_ENABLE 0x02000000
#define V2_CLOCK_MODEL_SPECIFIC 0x04000000
@ -78,82 +85,58 @@ int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
sizeof(reg));
}
static int detect_clock_source_optical_model(struct snd_motu *motu, u32 data,
enum snd_motu_clock_source *src)
{
switch (data) {
case 0:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case 1:
{
__be32 reg;
// To check the configuration of optical interface.
int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET,
&reg, sizeof(reg));
if (err < 0)
return err;
if (be32_to_cpu(reg) & 0x00000200)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
else
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
break;
}
case 2:
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
break;
case 3:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case 4:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
case 5:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
break;
default:
*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
break;
}
return 0;
}
static int v2_detect_clock_source(struct snd_motu *motu, u32 data,
enum snd_motu_clock_source *src)
{
switch (data) {
case 0:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case 2:
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
break;
case 3:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case 4:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
default:
*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
break;
}
return 0;
}
static int get_clock_source(struct snd_motu *motu, u32 data,
enum snd_motu_clock_source *src)
{
data &= V2_CLOCK_SRC_MASK;
if (motu->spec == &snd_motu_spec_828mk2 ||
motu->spec == &snd_motu_spec_traveler)
return detect_clock_source_optical_model(motu, data, src);
else
return v2_detect_clock_source(motu, data, src);
switch (data & V2_CLOCK_SRC_MASK) {
case V2_CLOCK_SRC_INTERNAL:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case V2_CLOCK_SRC_ADAT_ON_OPT:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
break;
case V2_CLOCK_SRC_SPDIF:
{
bool support_iec60958_on_opt = (motu->spec == &snd_motu_spec_828mk2 ||
motu->spec == &snd_motu_spec_traveler);
if (!support_iec60958_on_opt) {
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
} else {
__be32 reg;
// To check the configuration of optical interface.
int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
sizeof(reg));
if (err < 0)
return err;
if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_SPDIF)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
else
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
}
break;
}
case V2_CLOCK_SRC_SPH:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case V2_CLOCK_SRC_WORD_ON_BNC:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
case V2_CLOCK_SRC_ADAT_ON_DSUB:
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
break;
case V2_CLOCK_SRC_AESEBU_ON_XLR:
*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
break;
default:
*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
break;
}
return 0;
}
int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,
@ -235,59 +218,9 @@ int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,
}
}
static int detect_packet_formats_828mk2(struct snd_motu *motu, u32 data)
{
if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_ADAT) {
motu->tx_packet_formats.pcm_chunks[0] += 8;
motu->tx_packet_formats.pcm_chunks[1] += 4;
}
if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_ADAT) {
motu->rx_packet_formats.pcm_chunks[0] += 8;
motu->rx_packet_formats.pcm_chunks[1] += 4;
}
return 0;
}
static int detect_packet_formats_traveler(struct snd_motu *motu, u32 data)
{
if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_ADAT) {
motu->tx_packet_formats.pcm_chunks[0] += 8;
motu->tx_packet_formats.pcm_chunks[1] += 4;
}
if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_ADAT) {
motu->rx_packet_formats.pcm_chunks[0] += 8;
motu->rx_packet_formats.pcm_chunks[1] += 4;
}
return 0;
}
static int detect_packet_formats_8pre(struct snd_motu *motu, u32 data)
{
if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_ADAT) {
motu->tx_packet_formats.pcm_chunks[0] += 8;
motu->tx_packet_formats.pcm_chunks[1] += 8;
}
if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) ==
V2_OPT_IFACE_MODE_ADAT) {
motu->rx_packet_formats.pcm_chunks[0] += 8;
motu->rx_packet_formats.pcm_chunks[1] += 8;
}
return 0;
}
int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)
{
bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre);
__be32 reg;
u32 data;
int err;
@ -311,14 +244,25 @@ int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)
motu->spec->rx_fixed_pcm_chunks,
sizeof(motu->rx_packet_formats.pcm_chunks));
if (motu->spec == &snd_motu_spec_828mk2)
return detect_packet_formats_828mk2(motu, data);
else if (motu->spec == &snd_motu_spec_traveler)
return detect_packet_formats_traveler(motu, data);
else if (motu->spec == &snd_motu_spec_8pre)
return detect_packet_formats_8pre(motu, data);
else
return 0;
if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
motu->tx_packet_formats.pcm_chunks[0] += 8;
if (!has_two_opt_ifaces)
motu->tx_packet_formats.pcm_chunks[1] += 4;
else
motu->tx_packet_formats.pcm_chunks[1] += 8;
}
if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
motu->rx_packet_formats.pcm_chunks[0] += 8;
if (!has_two_opt_ifaces)
motu->rx_packet_formats.pcm_chunks[1] += 4;
else
motu->rx_packet_formats.pcm_chunks[1] += 8;
}
return 0;
}
const struct snd_motu_spec snd_motu_spec_828mk2 = {
@ -353,6 +297,7 @@ const struct snd_motu_spec snd_motu_spec_8pre = {
.protocol_version = SND_MOTU_PROTOCOL_V2,
.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_2ND_Q,
.tx_fixed_pcm_chunks = {10, 6, 0},
.rx_fixed_pcm_chunks = {10, 6, 0},
// Two dummy chunks always in the end of data block.
.tx_fixed_pcm_chunks = {10, 10, 0},
.rx_fixed_pcm_chunks = {6, 6, 0},
};

View File

@ -13,6 +13,12 @@
#define V3_CLOCK_RATE_MASK 0x0000ff00
#define V3_CLOCK_RATE_SHIFT 8
#define V3_CLOCK_SOURCE_MASK 0x000000ff
#define V3_CLOCK_SRC_INTERNAL 0x00
#define V3_CLOCK_SRC_WORD_ON_BNC 0x01
#define V3_CLOCK_SRC_SPH 0x02
#define V3_CLOCK_SRC_SPDIF_ON_COAX 0x10
#define V3_CLOCK_SRC_OPT_IFACE_A 0x18
#define V3_CLOCK_SRC_OPT_IFACE_B 0x19
#define V3_OPT_IFACE_MODE_OFFSET 0x0c94
#define V3_ENABLE_OPT_IN_IFACE_A 0x00000001
@ -97,81 +103,6 @@ int snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu,
return 0;
}
static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data,
enum snd_motu_clock_source *src)
{
switch (data) {
case 0x00:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case 0x01:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
case 0x02:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case 0x10:
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
break;
case 0x18:
case 0x19:
{
__be32 reg;
u32 options;
int err;
err = snd_motu_transaction_read(motu,
V3_OPT_IFACE_MODE_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
options = be32_to_cpu(reg);
if (data == 0x18) {
if (options & V3_NO_ADAT_OPT_IN_IFACE_A)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A;
else
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A;
} else {
if (options & V3_NO_ADAT_OPT_IN_IFACE_B)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B;
else
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B;
}
break;
}
default:
*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
break;
}
return 0;
}
static int v3_detect_clock_source(struct snd_motu *motu, u32 data,
enum snd_motu_clock_source *src)
{
switch (data) {
case 0x00:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case 0x01:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
case 0x02:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case 0x10:
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
break;
default:
*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
break;
}
return 0;
}
int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu,
enum snd_motu_clock_source *src)
{
@ -185,10 +116,50 @@ int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu,
return err;
data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK;
if (motu->spec == &snd_motu_spec_828mk3)
return detect_clock_source_828mk3(motu, data, src);
else
return v3_detect_clock_source(motu, data, src);
switch (data) {
case V3_CLOCK_SRC_INTERNAL:
*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
break;
case V3_CLOCK_SRC_WORD_ON_BNC:
*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
break;
case V3_CLOCK_SRC_SPH:
*src = SND_MOTU_CLOCK_SOURCE_SPH;
break;
case V3_CLOCK_SRC_SPDIF_ON_COAX:
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
break;
case V3_CLOCK_SRC_OPT_IFACE_A:
case V3_CLOCK_SRC_OPT_IFACE_B:
{
__be32 reg;
u32 options;
err = snd_motu_transaction_read(motu,
V3_OPT_IFACE_MODE_OFFSET, &reg, sizeof(reg));
if (err < 0)
return err;
options = be32_to_cpu(reg);
if (data == V3_CLOCK_SRC_OPT_IFACE_A) {
if (options & V3_NO_ADAT_OPT_IN_IFACE_A)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A;
else
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A;
} else {
if (options & V3_NO_ADAT_OPT_IN_IFACE_B)
*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B;
else
*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B;
}
break;
}
default:
*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
break;
}
return 0;
}
int snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu,
@ -284,14 +255,14 @@ int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
motu->spec->rx_fixed_pcm_chunks,
sizeof(motu->rx_packet_formats.pcm_chunks));
if (motu->spec == &snd_motu_spec_828mk3)
if (motu->spec == &snd_motu_spec_828mk3_fw || motu->spec == &snd_motu_spec_828mk3_hybrid)
return detect_packet_formats_828mk3(motu, data);
else
return 0;
}
const struct snd_motu_spec snd_motu_spec_828mk3 = {
const struct snd_motu_spec snd_motu_spec_828mk3_fw = {
.name = "828mk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,
.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
@ -300,6 +271,15 @@ const struct snd_motu_spec snd_motu_spec_828mk3 = {
.rx_fixed_pcm_chunks = {14, 14, 10},
};
const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = {
.name = "828mk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,
.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
SND_MOTU_SPEC_TX_MIDI_3RD_Q,
.tx_fixed_pcm_chunks = {18, 18, 14},
.rx_fixed_pcm_chunks = {14, 14, 14}, // Additional 4 dummy chunks at higher rate.
};
const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
.name = "UltraLiteMk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,

View File

@ -7,7 +7,7 @@
#include "motu.h"
#define CALLBACK_TIMEOUT 200
#define READY_TIMEOUT_MS 200
#define ISOC_COMM_CONTROL_OFFSET 0x0b00
#define ISOC_COMM_CONTROL_MASK 0xffff0000
@ -153,6 +153,9 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
fw_iso_resources_free(&motu->tx_resources);
fw_iso_resources_free(&motu->rx_resources);
kfree(motu->cache.event_offsets);
motu->cache.event_offsets = NULL;
err = snd_motu_protocol_set_clock_rate(motu, rate);
if (err < 0) {
dev_err(&motu->unit->device,
@ -181,6 +184,15 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
fw_iso_resources_free(&motu->rx_resources);
return err;
}
motu->cache.size = motu->tx_stream.syt_interval * frames_per_buffer;
motu->cache.event_offsets = kcalloc(motu->cache.size, sizeof(*motu->cache.event_offsets),
GFP_KERNEL);
if (!motu->cache.event_offsets) {
fw_iso_resources_free(&motu->tx_resources);
fw_iso_resources_free(&motu->rx_resources);
return -ENOMEM;
}
}
return 0;
@ -260,14 +272,19 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
if (err < 0)
goto stop_streams;
err = amdtp_domain_start(&motu->domain, 0);
motu->cache.tail = 0;
motu->cache.tx_cycle_count = UINT_MAX;
motu->cache.head = 0;
motu->cache.rx_cycle_count = UINT_MAX;
// NOTE: The device requires both of replay; the sequence of the number of data
// blocks per packet, and the sequence of source packet header per data block as
// presentation time.
err = amdtp_domain_start(&motu->domain, 0, true, false);
if (err < 0)
goto stop_streams;
if (!amdtp_stream_wait_callback(&motu->tx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&motu->rx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&motu->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto stop_streams;
}
@ -296,6 +313,9 @@ void snd_motu_stream_stop_duplex(struct snd_motu *motu)
fw_iso_resources_free(&motu->tx_resources);
fw_iso_resources_free(&motu->rx_resources);
kfree(motu->cache.event_offsets);
motu->cache.event_offsets = NULL;
}
}
@ -317,7 +337,7 @@ static int init_stream(struct snd_motu *motu, struct amdtp_stream *s)
if (err < 0)
return err;
err = amdtp_motu_init(s, motu->unit, dir, motu->spec);
err = amdtp_motu_init(s, motu->unit, dir, motu->spec, &motu->cache);
if (err < 0)
fw_iso_resources_destroy(resources);

View File

@ -57,22 +57,31 @@ static void motu_card_free(struct snd_card *card)
snd_motu_transaction_unregister(motu);
snd_motu_stream_destroy_duplex(motu);
mutex_destroy(&motu->mutex);
fw_unit_put(motu->unit);
}
static void do_registration(struct work_struct *work)
static int motu_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work);
struct snd_card *card;
struct snd_motu *motu;
int err;
if (motu->registered)
return;
err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0,
&motu->card);
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*motu), &card);
if (err < 0)
return;
motu->card->private_free = motu_card_free;
motu->card->private_data = motu;
return err;
card->private_free = motu_card_free;
motu = card->private_data;
motu->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, motu);
motu->card = card;
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
mutex_init(&motu->mutex);
spin_lock_init(&motu->lock);
init_waitqueue_head(&motu->hwdep_wait);
name_card(motu);
@ -103,71 +112,28 @@ static void do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(motu->card);
err = snd_card_register(card);
if (err < 0)
goto error;
motu->registered = true;
return;
error:
snd_card_free(motu->card);
dev_info(&motu->unit->device,
"Sound card registration failed: %d\n", err);
}
static int motu_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
{
struct snd_motu *motu;
/* Allocate this independently of sound card instance. */
motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL);
if (!motu)
return -ENOMEM;
motu->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, motu);
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
mutex_init(&motu->mutex);
spin_lock_init(&motu->lock);
init_waitqueue_head(&motu->hwdep_wait);
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&motu->dwork, do_registration);
snd_fw_schedule_registration(unit, &motu->dwork);
return 0;
error:
snd_card_free(card);
return err;
}
static void motu_remove(struct fw_unit *unit)
{
struct snd_motu *motu = dev_get_drvdata(&unit->device);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&motu->dwork);
if (motu->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(motu->card);
}
mutex_destroy(&motu->mutex);
fw_unit_put(motu->unit);
// Block till all of ALSA character devices are released.
snd_card_free(motu->card);
}
static void motu_bus_update(struct fw_unit *unit)
{
struct snd_motu *motu = dev_get_drvdata(&unit->device);
/* Postpone a workqueue for deferred registration. */
if (!motu->registered)
snd_fw_schedule_registration(unit, &motu->dwork);
/* The handler address register becomes initialized. */
snd_motu_transaction_reregister(motu);
}
@ -184,13 +150,16 @@ static void motu_bus_update(struct fw_unit *unit)
}
static const struct ieee1394_device_id motu_id_table[] = {
SND_MOTU_DEV_ENTRY(0x000001, &snd_motu_spec_828),
SND_MOTU_DEV_ENTRY(0x000002, &snd_motu_spec_896),
SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2),
SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite),
SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3), // FireWire only.
SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3_fw), // FireWire only.
SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only.
SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3), // Hybrid.
SND_MOTU_DEV_ENTRY(0x000030, &snd_motu_spec_ultralite_mk3), // Hybrid.
SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3_hybrid), // Hybrid.
SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express),
SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre),
{ }

View File

@ -39,15 +39,21 @@ struct snd_motu_packet_format {
unsigned char pcm_chunks[3];
};
struct amdtp_motu_cache {
unsigned int *event_offsets;
unsigned int size;
unsigned int tail;
unsigned int tx_cycle_count;
unsigned int head;
unsigned int rx_cycle_count;
};
struct snd_motu {
struct snd_card *card;
struct fw_unit *unit;
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
/* Model dependent information. */
const struct snd_motu_spec *spec;
@ -70,6 +76,8 @@ struct snd_motu {
wait_queue_head_t hwdep_wait;
struct amdtp_domain domain;
struct amdtp_motu_cache cache;
};
enum snd_motu_spec_flags {
@ -99,6 +107,7 @@ enum snd_motu_clock_source {
};
enum snd_motu_protocol_version {
SND_MOTU_PROTOCOL_V1,
SND_MOTU_PROTOCOL_V2,
SND_MOTU_PROTOCOL_V3,
};
@ -106,25 +115,31 @@ enum snd_motu_protocol_version {
struct snd_motu_spec {
const char *const name;
enum snd_motu_protocol_version protocol_version;
enum snd_motu_spec_flags flags;
// The combination of snd_motu_spec_flags enumeration-constants.
unsigned int flags;
unsigned char tx_fixed_pcm_chunks[3];
unsigned char rx_fixed_pcm_chunks[3];
};
extern const struct snd_motu_spec snd_motu_spec_828;
extern const struct snd_motu_spec snd_motu_spec_896;
extern const struct snd_motu_spec snd_motu_spec_828mk2;
extern const struct snd_motu_spec snd_motu_spec_traveler;
extern const struct snd_motu_spec snd_motu_spec_ultralite;
extern const struct snd_motu_spec snd_motu_spec_8pre;
extern const struct snd_motu_spec snd_motu_spec_828mk3;
extern const struct snd_motu_spec snd_motu_spec_828mk3_fw;
extern const struct snd_motu_spec snd_motu_spec_828mk3_hybrid;
extern const struct snd_motu_spec snd_motu_spec_ultralite_mk3;
extern const struct snd_motu_spec snd_motu_spec_audio_express;
extern const struct snd_motu_spec snd_motu_spec_4pre;
int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir,
const struct snd_motu_spec *spec);
const struct snd_motu_spec *spec,
struct amdtp_motu_cache *cache);
int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
unsigned int midi_ports,
struct snd_motu_packet_format *formats);
@ -160,6 +175,16 @@ int snd_motu_create_midi_devices(struct snd_motu *motu);
int snd_motu_create_hwdep_device(struct snd_motu *motu);
int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu,
unsigned int *rate);
int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu,
unsigned int rate);
int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu,
enum snd_motu_clock_source *src);
int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu,
bool enable);
int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu);
int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
unsigned int *rate);
int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
@ -187,6 +212,8 @@ static inline int snd_motu_protocol_get_clock_rate(struct snd_motu *motu,
return snd_motu_protocol_v2_get_clock_rate(motu, rate);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
return snd_motu_protocol_v3_get_clock_rate(motu, rate);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
return snd_motu_protocol_v1_get_clock_rate(motu, rate);
else
return -ENXIO;
}
@ -198,6 +225,8 @@ static inline int snd_motu_protocol_set_clock_rate(struct snd_motu *motu,
return snd_motu_protocol_v2_set_clock_rate(motu, rate);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
return snd_motu_protocol_v3_set_clock_rate(motu, rate);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
return snd_motu_protocol_v1_set_clock_rate(motu, rate);
else
return -ENXIO;
}
@ -209,6 +238,8 @@ static inline int snd_motu_protocol_get_clock_source(struct snd_motu *motu,
return snd_motu_protocol_v2_get_clock_source(motu, source);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
return snd_motu_protocol_v3_get_clock_source(motu, source);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
return snd_motu_protocol_v1_get_clock_source(motu, source);
else
return -ENXIO;
}
@ -220,6 +251,8 @@ static inline int snd_motu_protocol_switch_fetching_mode(struct snd_motu *motu,
return snd_motu_protocol_v2_switch_fetching_mode(motu, enable);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
return snd_motu_protocol_v3_switch_fetching_mode(motu, enable);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
return snd_motu_protocol_v1_switch_fetching_mode(motu, enable);
else
return -ENXIO;
}
@ -230,6 +263,8 @@ static inline int snd_motu_protocol_cache_packet_formats(struct snd_motu *motu)
return snd_motu_protocol_v2_cache_packet_formats(motu);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3)
return snd_motu_protocol_v3_cache_packet_formats(motu);
else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1)
return snd_motu_protocol_v1_cache_packet_formats(motu);
else
return -ENXIO;
}

View File

@ -9,7 +9,7 @@
#include <linux/delay.h>
#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
#define CALLBACK_TIMEOUT 200
#define READY_TIMEOUT_MS 200
/*
* According to datasheet of Oxford Semiconductor:
@ -153,12 +153,23 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
struct cmp_connection *conn;
enum cmp_direction c_dir;
enum amdtp_stream_direction s_dir;
unsigned int flags = CIP_UNAWARE_SYT;
int err;
if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION))
flags |= CIP_NONBLOCKING;
else
flags |= CIP_BLOCKING;
if (stream == &oxfw->tx_stream) {
conn = &oxfw->out_conn;
c_dir = CMP_OUTPUT;
s_dir = AMDTP_IN_STREAM;
if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD)
flags |= CIP_JUMBO_PAYLOAD;
if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS)
flags |= CIP_WRONG_DBS;
} else {
conn = &oxfw->in_conn;
c_dir = CMP_INPUT;
@ -169,24 +180,12 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
if (err < 0)
return err;
err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags);
if (err < 0) {
cmp_connection_destroy(conn);
return err;
}
/*
* OXFW starts to transmit packets with non-zero dbc.
* OXFW postpone transferring packets till handling any asynchronous
* packets. As a result, next isochronous packet includes more data
* blocks than IEC 61883-6 defines.
*/
if (stream == &oxfw->tx_stream) {
oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD;
if (oxfw->wrong_dbs)
oxfw->tx_stream.flags |= CIP_WRONG_DBS;
}
return 0;
}
@ -338,6 +337,9 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
}
if (!amdtp_stream_running(&oxfw->rx_stream)) {
unsigned int tx_init_skip_cycles = 0;
bool replay_seq = false;
err = start_stream(oxfw, &oxfw->rx_stream);
if (err < 0) {
dev_err(&oxfw->unit->device,
@ -353,26 +355,27 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
"fail to prepare tx stream: %d\n", err);
goto error;
}
if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) {
// Just after changing sampling transfer frequency, many cycles are
// skipped for packet transmission.
tx_init_skip_cycles = 400;
} else {
replay_seq = true;
}
}
err = amdtp_domain_start(&oxfw->domain, 0);
// NOTE: The device ignores presentation time expressed by the value of syt field
// of CIP header in received packets. The sequence of the number of data blocks per
// packet is important for media clock recovery.
err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false);
if (err < 0)
goto error;
// Wait first packet.
if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
if (oxfw->has_output) {
if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
CALLBACK_TIMEOUT)) {
err = -ETIMEDOUT;
goto error;
}
}
}
return 0;

View File

@ -23,6 +23,8 @@
#define OUI_APOGEE 0x0003db
#define MODEL_SATELLITE 0x00200f
#define MODEL_SCS1M 0x001000
#define MODEL_DUET_FW 0x01dddd
#define SPECIFIER_1394TA 0x00a02d
#define VERSION_AVC 0x010001
@ -46,8 +48,6 @@ static bool detect_loud_models(struct fw_unit *unit)
"Onyx-i",
"Onyx 1640i",
"d.Pro",
"Mackie Onyx Satellite",
"Tapco LINK.firewire 4x6",
"U.420"};
char model[32];
int err;
@ -60,7 +60,7 @@ static bool detect_loud_models(struct fw_unit *unit)
return match_string(models, ARRAY_SIZE(models), model) >= 0;
}
static int name_card(struct snd_oxfw *oxfw)
static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry)
{
struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
const struct compat_info *info;
@ -88,10 +88,12 @@ static int name_card(struct snd_oxfw *oxfw)
goto end;
be32_to_cpus(&firmware);
if (firmware >> 20 == 0x970)
oxfw->quirks |= SND_OXFW_QUIRK_JUMBO_PAYLOAD;
/* to apply card definitions */
if (oxfw->entry->vendor_id == VENDOR_GRIFFIN ||
oxfw->entry->vendor_id == VENDOR_LACIE) {
info = (const struct compat_info *)oxfw->entry->driver_data;
if (entry->vendor_id == VENDOR_GRIFFIN || entry->vendor_id == VENDOR_LACIE) {
info = (const struct compat_info *)entry->driver_data;
d = info->driver_name;
v = info->vendor_name;
m = info->model_name;
@ -120,9 +122,12 @@ static void oxfw_card_free(struct snd_card *card)
if (oxfw->has_output || oxfw->has_input)
snd_oxfw_stream_destroy_duplex(oxfw);
mutex_destroy(&oxfw->mutex);
fw_unit_put(oxfw->unit);
}
static int detect_quirks(struct snd_oxfw *oxfw)
static int detect_quirks(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry)
{
struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
struct fw_csr_iterator it;
@ -133,28 +138,35 @@ static int detect_quirks(struct snd_oxfw *oxfw)
* Add ALSA control elements for two models to keep compatibility to
* old firewire-speaker module.
*/
if (oxfw->entry->vendor_id == VENDOR_GRIFFIN)
if (entry->vendor_id == VENDOR_GRIFFIN)
return snd_oxfw_add_spkr(oxfw, false);
if (oxfw->entry->vendor_id == VENDOR_LACIE)
if (entry->vendor_id == VENDOR_LACIE)
return snd_oxfw_add_spkr(oxfw, true);
/*
* Stanton models supports asynchronous transactions for unique MIDI
* messages.
*/
if (oxfw->entry->vendor_id == OUI_STANTON) {
/* No physical MIDI ports. */
if (entry->vendor_id == OUI_STANTON) {
oxfw->quirks |= SND_OXFW_QUIRK_SCS_TRANSACTION;
if (entry->model_id == MODEL_SCS1M)
oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION;
// No physical MIDI ports.
oxfw->midi_input_ports = 0;
oxfw->midi_output_ports = 0;
return snd_oxfw_scs1x_add(oxfw);
}
if (entry->vendor_id == OUI_APOGEE && entry->model_id == MODEL_DUET_FW)
oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION;
/*
* TASCAM FireOne has physical control and requires a pair of additional
* MIDI ports.
*/
if (oxfw->entry->vendor_id == VENDOR_TASCAM) {
if (entry->vendor_id == VENDOR_TASCAM) {
oxfw->midi_input_ports++;
oxfw->midi_output_ports++;
return 0;
@ -175,27 +187,35 @@ static int detect_quirks(struct snd_oxfw *oxfw)
* value in 'dbs' field of CIP header against its format information.
*/
if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE)
oxfw->wrong_dbs = true;
oxfw->quirks |= SND_OXFW_QUIRK_WRONG_DBS;
return 0;
}
static void do_registration(struct work_struct *work)
static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
struct snd_card *card;
struct snd_oxfw *oxfw;
int err;
if (oxfw->registered)
return;
if (entry->vendor_id == VENDOR_LOUD && entry->model_id == 0 && !detect_loud_models(unit))
return -ENODEV;
err = snd_card_new(&oxfw->unit->device, -1, NULL, THIS_MODULE, 0,
&oxfw->card);
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*oxfw), &card);
if (err < 0)
return;
oxfw->card->private_free = oxfw_card_free;
oxfw->card->private_data = oxfw;
return err;
card->private_free = oxfw_card_free;
err = name_card(oxfw);
oxfw = card->private_data;
oxfw->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, oxfw);
oxfw->card = card;
mutex_init(&oxfw->mutex);
spin_lock_init(&oxfw->lock);
init_waitqueue_head(&oxfw->hwdep_wait);
err = name_card(oxfw, entry);
if (err < 0)
goto error;
@ -203,7 +223,7 @@ static void do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = detect_quirks(oxfw);
err = detect_quirks(oxfw, entry);
if (err < 0)
goto error;
@ -227,85 +247,38 @@ static void do_registration(struct work_struct *work)
goto error;
}
err = snd_card_register(oxfw->card);
err = snd_card_register(card);
if (err < 0)
goto error;
oxfw->registered = true;
return;
error:
snd_card_free(oxfw->card);
dev_info(&oxfw->unit->device,
"Sound card registration failed: %d\n", err);
}
static int oxfw_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
{
struct snd_oxfw *oxfw;
if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit))
return -ENODEV;
/* Allocate this independent of sound card instance. */
oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL);
if (!oxfw)
return -ENOMEM;
oxfw->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, oxfw);
oxfw->entry = entry;
mutex_init(&oxfw->mutex);
spin_lock_init(&oxfw->lock);
init_waitqueue_head(&oxfw->hwdep_wait);
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&oxfw->dwork, do_registration);
snd_fw_schedule_registration(unit, &oxfw->dwork);
return 0;
error:
snd_card_free(card);
return err;
}
static void oxfw_bus_reset(struct fw_unit *unit)
{
struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
if (!oxfw->registered)
snd_fw_schedule_registration(unit, &oxfw->dwork);
fcp_bus_reset(oxfw->unit);
if (oxfw->registered) {
if (oxfw->has_output || oxfw->has_input) {
mutex_lock(&oxfw->mutex);
snd_oxfw_stream_update_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
}
if (oxfw->entry->vendor_id == OUI_STANTON)
snd_oxfw_scs1x_update(oxfw);
if (oxfw->has_output || oxfw->has_input) {
mutex_lock(&oxfw->mutex);
snd_oxfw_stream_update_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
}
if (oxfw->quirks & SND_OXFW_QUIRK_SCS_TRANSACTION)
snd_oxfw_scs1x_update(oxfw);
}
static void oxfw_remove(struct fw_unit *unit)
{
struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&oxfw->dwork);
if (oxfw->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(oxfw->card);
}
mutex_destroy(&oxfw->mutex);
fw_unit_put(oxfw->unit);
// Block till all of ALSA character devices are released.
snd_card_free(oxfw->card);
}
static const struct compat_info griffin_firewave = {
@ -320,81 +293,67 @@ static const struct compat_info lacie_speakers = {
.model_name = "FireWire Speakers",
};
#define OXFW_DEV_ENTRY(vendor, model, data) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID | \
IEEE1394_MATCH_SPECIFIER_ID | \
IEEE1394_MATCH_VERSION, \
.vendor_id = vendor, \
.model_id = model, \
.specifier_id = SPECIFIER_1394TA, \
.version = VERSION_AVC, \
.driver_data = (kernel_ulong_t)data, \
}
static const struct ieee1394_device_id oxfw_id_table[] = {
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.vendor_id = VENDOR_GRIFFIN,
.model_id = 0x00f970,
.specifier_id = SPECIFIER_1394TA,
.version = VERSION_AVC,
.driver_data = (kernel_ulong_t)&griffin_firewave,
},
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.vendor_id = VENDOR_LACIE,
.model_id = 0x00f970,
.specifier_id = SPECIFIER_1394TA,
.version = VERSION_AVC,
.driver_data = (kernel_ulong_t)&lacie_speakers,
},
/* Behringer,F-Control Audio 202 */
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = VENDOR_BEHRINGER,
.model_id = 0x00fc22,
},
/*
* Any Mackie(Loud) models (name string/model id):
* Onyx-i series (former models): 0x081216
* Mackie Onyx Satellite: 0x00200f
* Tapco LINK.firewire 4x6: 0x000460
* d.4 pro: Unknown
* U.420: Unknown
* U.420d: Unknown
*/
//
// OXFW970 devices:
// Initial firmware has a quirk to postpone isoc packet transmission during finishing async
// transaction. As a result, several isochronous cycles are skipped to transfer the packets
// and the audio data frames which should have been transferred during the cycles are put
// into packet at the first isoc cycle after the postpone. Furthermore, the value of SYT
// field in CIP header is not reliable as synchronization timing,
//
OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave),
OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers),
// Behringer,F-Control Audio 202. The value of SYT field is not reliable at all.
OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL),
// Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff.
OXFW_DEV_ENTRY(VENDOR_LOUD, 0x000460, NULL),
// Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is
// installed to avoid the postpone, the value of SYT field is always 0xffff.
OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL),
// Miglia HarmonyAudio. Not yet identified.
//
// OXFW971 devices:
// The value of SYT field in CIP header is enough reliable. Both of blocking and non-blocking
// transmission methods are available.
//
// Any Mackie(Loud) models (name string/model id):
// Onyx-i series (former models): 0x081216
// Onyx 1640i: 0x001640
// d.2 pro/d.4 pro (built-in card): Unknown
// U.420: Unknown
// U.420d: Unknown
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.vendor_id = VENDOR_LOUD,
.model_id = 0,
.specifier_id = SPECIFIER_1394TA,
.version = VERSION_AVC,
},
/* TASCAM, FireOne */
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = VENDOR_TASCAM,
.model_id = 0x800007,
},
/* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = OUI_STANTON,
.model_id = 0x001000,
},
/* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = OUI_STANTON,
.model_id = 0x002000,
},
// APOGEE, duet FireWire
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = OUI_APOGEE,
.model_id = 0x01dddd,
},
// TASCAM, FireOne.
OXFW_DEV_ENTRY(VENDOR_TASCAM, 0x800007, NULL),
// Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m).
OXFW_DEV_ENTRY(OUI_STANTON, MODEL_SCS1M, NULL),
// Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d).
OXFW_DEV_ENTRY(OUI_STANTON, 0x002000, NULL),
// APOGEE, duet FireWire.
OXFW_DEV_ENTRY(OUI_APOGEE, MODEL_DUET_FW, NULL),
{ }
};
MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);

Some files were not shown because too many files have changed in this diff Show More