2019-05-30 07:57:59 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2015-10-01 21:02:11 +08:00
|
|
|
/*
|
|
|
|
* tascam.h - a part of driver for TASCAM FireWire series
|
|
|
|
*
|
|
|
|
* Copyright (c) 2015 Takashi Sakamoto
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SOUND_TASCAM_H_INCLUDED
|
|
|
|
#define SOUND_TASCAM_H_INCLUDED
|
|
|
|
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/firewire.h>
|
|
|
|
#include <linux/firewire-constants.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/mod_devicetable.h>
|
|
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/compat.h>
|
2017-02-03 02:15:33 +08:00
|
|
|
#include <linux/sched/signal.h>
|
2015-10-01 21:02:11 +08:00
|
|
|
|
|
|
|
#include <sound/core.h>
|
|
|
|
#include <sound/initval.h>
|
2015-10-01 21:02:13 +08:00
|
|
|
#include <sound/info.h>
|
2015-10-01 21:02:14 +08:00
|
|
|
#include <sound/pcm.h>
|
|
|
|
#include <sound/pcm_params.h>
|
2015-10-01 21:02:17 +08:00
|
|
|
#include <sound/firewire.h>
|
|
|
|
#include <sound/hwdep.h>
|
2015-10-12 18:10:21 +08:00
|
|
|
#include <sound/rawmidi.h>
|
2015-10-01 21:02:11 +08:00
|
|
|
|
|
|
|
#include "../lib.h"
|
2015-10-01 21:02:14 +08:00
|
|
|
#include "../amdtp-stream.h"
|
2015-10-01 21:02:15 +08:00
|
|
|
#include "../iso-resources.h"
|
2015-10-01 21:02:11 +08:00
|
|
|
|
2015-10-01 21:02:12 +08:00
|
|
|
struct snd_tscm_spec {
|
|
|
|
const char *const name;
|
|
|
|
bool has_adat;
|
|
|
|
bool has_spdif;
|
|
|
|
unsigned int pcm_capture_analog_channels;
|
|
|
|
unsigned int pcm_playback_analog_channels;
|
|
|
|
unsigned int midi_capture_ports;
|
|
|
|
unsigned int midi_playback_ports;
|
|
|
|
};
|
|
|
|
|
2015-10-12 18:10:21 +08:00
|
|
|
#define TSCM_MIDI_IN_PORT_MAX 4
|
|
|
|
#define TSCM_MIDI_OUT_PORT_MAX 4
|
|
|
|
|
2017-04-14 15:46:25 +08:00
|
|
|
struct snd_fw_async_midi_port {
|
|
|
|
struct fw_device *parent;
|
|
|
|
struct work_struct work;
|
|
|
|
bool idling;
|
|
|
|
ktime_t next_ktime;
|
|
|
|
bool error;
|
|
|
|
|
|
|
|
struct fw_transaction transaction;
|
|
|
|
|
2017-04-14 15:46:29 +08:00
|
|
|
u8 buf[4];
|
2017-04-14 15:46:31 +08:00
|
|
|
u8 running_status;
|
|
|
|
bool on_sysex;
|
2017-04-14 15:46:25 +08:00
|
|
|
|
|
|
|
struct snd_rawmidi_substream *substream;
|
|
|
|
int consume_bytes;
|
|
|
|
};
|
|
|
|
|
2018-11-23 12:13:05 +08:00
|
|
|
#define SND_TSCM_QUEUE_COUNT 16
|
|
|
|
|
2015-10-01 21:02:11 +08:00
|
|
|
struct snd_tscm {
|
|
|
|
struct snd_card *card;
|
|
|
|
struct fw_unit *unit;
|
|
|
|
|
|
|
|
struct mutex mutex;
|
2015-10-01 21:02:17 +08:00
|
|
|
spinlock_t lock;
|
2015-10-01 21:02:12 +08:00
|
|
|
|
2016-03-31 07:47:09 +08:00
|
|
|
bool registered;
|
|
|
|
struct delayed_work dwork;
|
2015-10-01 21:02:12 +08:00
|
|
|
const struct snd_tscm_spec *spec;
|
2015-10-01 21:02:15 +08:00
|
|
|
|
|
|
|
struct fw_iso_resources tx_resources;
|
|
|
|
struct fw_iso_resources rx_resources;
|
|
|
|
struct amdtp_stream tx_stream;
|
|
|
|
struct amdtp_stream rx_stream;
|
|
|
|
unsigned int substreams_counter;
|
2015-10-01 21:02:17 +08:00
|
|
|
|
|
|
|
int dev_lock_count;
|
|
|
|
bool dev_lock_changed;
|
|
|
|
wait_queue_head_t hwdep_wait;
|
2015-10-12 18:10:21 +08:00
|
|
|
|
|
|
|
/* For MIDI message incoming transactions. */
|
|
|
|
struct fw_address_handler async_handler;
|
|
|
|
struct snd_rawmidi_substream *tx_midi_substreams[TSCM_MIDI_IN_PORT_MAX];
|
2015-10-12 18:10:22 +08:00
|
|
|
|
|
|
|
/* For MIDI message outgoing transactions. */
|
|
|
|
struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
|
2018-11-23 12:13:03 +08:00
|
|
|
|
|
|
|
// A cache of status information in tx isoc packets.
|
|
|
|
__be32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
|
2018-11-23 12:13:05 +08:00
|
|
|
struct snd_hwdep *hwdep;
|
|
|
|
struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT];
|
|
|
|
unsigned int pull_pos;
|
|
|
|
unsigned int push_pos;
|
2019-08-04 14:21:35 +08:00
|
|
|
|
|
|
|
struct amdtp_domain domain;
|
2015-10-01 21:02:11 +08:00
|
|
|
};
|
|
|
|
|
2015-10-01 21:02:13 +08:00
|
|
|
#define TSCM_ADDR_BASE 0xffff00000000ull
|
|
|
|
|
|
|
|
#define TSCM_OFFSET_FIRMWARE_REGISTER 0x0000
|
|
|
|
#define TSCM_OFFSET_FIRMWARE_FPGA 0x0004
|
|
|
|
#define TSCM_OFFSET_FIRMWARE_ARM 0x0008
|
|
|
|
#define TSCM_OFFSET_FIRMWARE_HW 0x000c
|
|
|
|
|
2015-10-01 21:02:15 +08:00
|
|
|
#define TSCM_OFFSET_ISOC_TX_CH 0x0200
|
|
|
|
#define TSCM_OFFSET_UNKNOWN 0x0204
|
|
|
|
#define TSCM_OFFSET_START_STREAMING 0x0208
|
|
|
|
#define TSCM_OFFSET_ISOC_RX_CH 0x020c
|
|
|
|
#define TSCM_OFFSET_ISOC_RX_ON 0x0210 /* Little conviction. */
|
|
|
|
#define TSCM_OFFSET_TX_PCM_CHANNELS 0x0214
|
|
|
|
#define TSCM_OFFSET_RX_PCM_CHANNELS 0x0218
|
|
|
|
#define TSCM_OFFSET_MULTIPLEX_MODE 0x021c
|
|
|
|
#define TSCM_OFFSET_ISOC_TX_ON 0x0220
|
|
|
|
/* Unknown 0x0224 */
|
|
|
|
#define TSCM_OFFSET_CLOCK_STATUS 0x0228
|
|
|
|
#define TSCM_OFFSET_SET_OPTION 0x022c
|
|
|
|
|
2015-10-12 18:10:21 +08:00
|
|
|
#define TSCM_OFFSET_MIDI_TX_ON 0x0300
|
|
|
|
#define TSCM_OFFSET_MIDI_TX_ADDR_HI 0x0304
|
|
|
|
#define TSCM_OFFSET_MIDI_TX_ADDR_LO 0x0308
|
|
|
|
|
2015-10-12 18:10:24 +08:00
|
|
|
#define TSCM_OFFSET_LED_POWER 0x0404
|
|
|
|
|
2015-10-12 18:10:21 +08:00
|
|
|
#define TSCM_OFFSET_MIDI_RX_QUAD 0x4000
|
|
|
|
|
ALSA: firewire-tascam: add note for FE-8
TASCAM FE-8 is the rest of model in TASCAM FireWire series. This device
has no functionality to process audio signal and MIDI messages. Instead,
it transfers control messages to host system corresponding to operations
for some faders, buttons and knobs on its surface.
Unlike the other devices in this series, the control messages are
transmitted by asynchronous transactions. Some registers of device are
used for registration of destination address for the transaction. The
transaction includes quadlet-aligned data up to 32 quadlets.
Userspace applications can receive the transaction and parse it for
control message via Linux FireWire subsystem, without any support by
ALSA firewire-tascam driver. Therefore the driver gives no support
for it.
This commit removes placeholder for FE-8 and add some comment for its
functionalities as notes.
$ python2 linux-firewire-utils/src/crpp < ~/git/am-config-rom/tascam/tascam-fe8.img
ROM header and bus information block
-----------------------------------------------------------------
400 040f4798 bus_info_length 4, crc_length 15, crc 18328 (should be 14256)
404 31333934 bus_name "1394"
408 20ff7002 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 7 (256)
40c 00022eff company_id 00022e |
410 a094dcb7 device_id ffa094dcb7 | EUI-64 00022effa094dcb7
root directory
-----------------------------------------------------------------
414 0004bccc directory_length 4, crc 48332
418 0300022e vendor
41c 0c0083c0 node capabilities per IEEE 1394
420 8d000006 --> eui-64 leaf at 438
424 d1000001 --> unit directory at 428
unit directory at 428
-----------------------------------------------------------------
428 0003eda4 directory_length 3, crc 60836
42c 1200022e specifier id
430 13800001 version
434 d4000004 --> dependent info directory at 444
eui-64 leaf at 438
-----------------------------------------------------------------
438 0002461e leaf_length 2, crc 17950
43c 00022eff company_id 00022e |
440 a094dcb7 device_id ffa094dcb7 | EUI-64 00022effa094dcb7
dependent info directory at 444
-----------------------------------------------------------------
444 0002ae47 directory_length 2, crc 44615
448 81000002 --> descriptor leaf at 450
44c 82000006 --> bus dependent info leaf at 464
descriptor leaf at 450
-----------------------------------------------------------------
450 0004a79e leaf_length 4, crc 42910
454 00000000 textual descriptor
458 00000000 minimal ASCII
45c 54415343 "TASC"
460 414d0000 "AM"
bus dependent info leaf at 464
-----------------------------------------------------------------
464 0004a7d8 leaf_length 4, crc 42968
468 00000000
46c 00000000
470 46452d38
474 00000000
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20190906125544.13800-1-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2019-09-06 20:55:44 +08:00
|
|
|
// Although FE-8 supports the above registers, it has no I/O interfaces for
|
|
|
|
// audio samples and music messages. Otherwise it supports another notification
|
|
|
|
// for status and control message as well as LED brightening. The message
|
|
|
|
// consists of quadlet-aligned data up to 32 quadlets. The first byte of message
|
|
|
|
// is fixed to 0x40. The second byte is between 0x00 to 0x1f and represent each
|
|
|
|
// control:
|
|
|
|
// fader: 0x00-0x07
|
|
|
|
// button: 0x0d, 0x0e
|
|
|
|
// knob: 0x14-0x1b
|
|
|
|
// sensing: 0x0b
|
|
|
|
//
|
|
|
|
// The rest two bytes represent state of the controls; e.g. current value for
|
|
|
|
// fader and knob, bitmasks for button and sensing.
|
|
|
|
// Just after turning on, 32 quadlets messages with 0x00-0x1f are immediately
|
|
|
|
// sent in one transaction. After, several quadlets are sent in one transaction.
|
|
|
|
//
|
|
|
|
// TSCM_OFFSET_FE8_CTL_TX_ON 0x0310
|
|
|
|
// TSCM_OFFSET_FE8_CTL_TX_ADDR_HI 0x0314
|
|
|
|
// TSCM_OFFSET_FE8_CTL_TX_ADDR_LO 0x0318
|
|
|
|
|
2015-10-01 21:02:15 +08:00
|
|
|
enum snd_tscm_clock {
|
|
|
|
SND_TSCM_CLOCK_INTERNAL = 0,
|
|
|
|
SND_TSCM_CLOCK_WORD = 1,
|
|
|
|
SND_TSCM_CLOCK_SPDIF = 2,
|
|
|
|
SND_TSCM_CLOCK_ADAT = 3,
|
|
|
|
};
|
|
|
|
|
2015-10-01 21:02:14 +08:00
|
|
|
int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
|
|
|
|
enum amdtp_stream_direction dir, unsigned int pcm_channels);
|
|
|
|
int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate);
|
|
|
|
int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
|
|
|
|
struct snd_pcm_runtime *runtime);
|
|
|
|
|
2015-10-01 21:02:15 +08:00
|
|
|
int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate);
|
|
|
|
int snd_tscm_stream_get_clock(struct snd_tscm *tscm,
|
|
|
|
enum snd_tscm_clock *clock);
|
|
|
|
int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
|
|
|
|
void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
|
|
|
|
void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
|
2019-10-07 19:05:22 +08:00
|
|
|
int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
|
2019-10-17 23:54:19 +08:00
|
|
|
unsigned int frames_per_period,
|
|
|
|
unsigned int frames_per_buffer);
|
2015-10-01 21:02:15 +08:00
|
|
|
int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
|
|
|
|
void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);
|
|
|
|
|
2015-10-01 21:02:17 +08:00
|
|
|
void snd_tscm_stream_lock_changed(struct snd_tscm *tscm);
|
|
|
|
int snd_tscm_stream_lock_try(struct snd_tscm *tscm);
|
|
|
|
void snd_tscm_stream_lock_release(struct snd_tscm *tscm);
|
|
|
|
|
2017-04-14 15:46:30 +08:00
|
|
|
void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port);
|
2017-04-14 15:46:25 +08:00
|
|
|
|
|
|
|
static inline void
|
|
|
|
snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port,
|
|
|
|
struct snd_rawmidi_substream *substream)
|
|
|
|
{
|
|
|
|
if (!port->error) {
|
|
|
|
port->substream = substream;
|
|
|
|
schedule_work(&port->work);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port)
|
|
|
|
{
|
|
|
|
port->substream = NULL;
|
2017-04-14 15:46:29 +08:00
|
|
|
cancel_work_sync(&port->work);
|
2017-04-14 15:46:25 +08:00
|
|
|
port->error = false;
|
|
|
|
}
|
|
|
|
|
2015-10-12 18:10:21 +08:00
|
|
|
int snd_tscm_transaction_register(struct snd_tscm *tscm);
|
|
|
|
int snd_tscm_transaction_reregister(struct snd_tscm *tscm);
|
|
|
|
void snd_tscm_transaction_unregister(struct snd_tscm *tscm);
|
|
|
|
|
2015-10-01 21:02:13 +08:00
|
|
|
void snd_tscm_proc_init(struct snd_tscm *tscm);
|
|
|
|
|
2015-10-01 21:02:16 +08:00
|
|
|
int snd_tscm_create_pcm_devices(struct snd_tscm *tscm);
|
|
|
|
|
2015-10-12 18:10:23 +08:00
|
|
|
int snd_tscm_create_midi_devices(struct snd_tscm *tscm);
|
|
|
|
|
2015-10-01 21:02:17 +08:00
|
|
|
int snd_tscm_create_hwdep_device(struct snd_tscm *tscm);
|
|
|
|
|
2015-10-01 21:02:11 +08:00
|
|
|
#endif
|