1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * tascam.h - a part of driver for TASCAM FireWire series |
4 | * |
5 | * Copyright (c) 2015 Takashi Sakamoto |
6 | */ |
7 | |
8 | #ifndef SOUND_TASCAM_H_INCLUDED |
9 | #define SOUND_TASCAM_H_INCLUDED |
10 | |
11 | #include <linux/device.h> |
12 | #include <linux/firewire.h> |
13 | #include <linux/firewire-constants.h> |
14 | #include <linux/module.h> |
15 | #include <linux/mod_devicetable.h> |
16 | #include <linux/mutex.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/compat.h> |
19 | #include <linux/sched/signal.h> |
20 | |
21 | #include <sound/core.h> |
22 | #include <sound/initval.h> |
23 | #include <sound/info.h> |
24 | #include <sound/pcm.h> |
25 | #include <sound/pcm_params.h> |
26 | #include <sound/firewire.h> |
27 | #include <sound/hwdep.h> |
28 | #include <sound/rawmidi.h> |
29 | |
30 | #include "../lib.h" |
31 | #include "../amdtp-stream.h" |
32 | #include "../iso-resources.h" |
33 | |
34 | struct snd_tscm_spec { |
35 | const char *const name; |
36 | bool has_adat; |
37 | bool has_spdif; |
38 | unsigned int pcm_capture_analog_channels; |
39 | unsigned int pcm_playback_analog_channels; |
40 | unsigned int midi_capture_ports; |
41 | unsigned int midi_playback_ports; |
42 | }; |
43 | |
44 | #define TSCM_MIDI_IN_PORT_MAX 4 |
45 | #define TSCM_MIDI_OUT_PORT_MAX 4 |
46 | |
47 | struct snd_fw_async_midi_port { |
48 | struct fw_device *parent; |
49 | struct work_struct work; |
50 | bool idling; |
51 | ktime_t next_ktime; |
52 | bool error; |
53 | |
54 | struct fw_transaction transaction; |
55 | |
56 | u8 buf[4]; |
57 | u8 running_status; |
58 | bool on_sysex; |
59 | |
60 | struct snd_rawmidi_substream *substream; |
61 | int consume_bytes; |
62 | }; |
63 | |
64 | #define SND_TSCM_QUEUE_COUNT 16 |
65 | |
66 | struct snd_tscm { |
67 | struct snd_card *card; |
68 | struct fw_unit *unit; |
69 | |
70 | struct mutex mutex; |
71 | spinlock_t lock; |
72 | |
73 | const struct snd_tscm_spec *spec; |
74 | |
75 | struct fw_iso_resources tx_resources; |
76 | struct fw_iso_resources rx_resources; |
77 | struct amdtp_stream tx_stream; |
78 | struct amdtp_stream rx_stream; |
79 | unsigned int substreams_counter; |
80 | |
81 | int dev_lock_count; |
82 | bool dev_lock_changed; |
83 | wait_queue_head_t hwdep_wait; |
84 | |
85 | /* For MIDI message incoming transactions. */ |
86 | struct fw_address_handler async_handler; |
87 | struct snd_rawmidi_substream *tx_midi_substreams[TSCM_MIDI_IN_PORT_MAX]; |
88 | |
89 | /* For MIDI message outgoing transactions. */ |
90 | struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX]; |
91 | |
92 | // A cache of status information in tx isoc packets. |
93 | __be32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT]; |
94 | struct snd_hwdep *hwdep; |
95 | struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT]; |
96 | unsigned int pull_pos; |
97 | unsigned int push_pos; |
98 | |
99 | struct amdtp_domain domain; |
100 | bool need_long_tx_init_skip; |
101 | }; |
102 | |
103 | #define TSCM_ADDR_BASE 0xffff00000000ull |
104 | |
105 | #define TSCM_OFFSET_FIRMWARE_REGISTER 0x0000 |
106 | #define TSCM_OFFSET_FIRMWARE_FPGA 0x0004 |
107 | #define TSCM_OFFSET_FIRMWARE_ARM 0x0008 |
108 | #define TSCM_OFFSET_FIRMWARE_HW 0x000c |
109 | |
110 | #define TSCM_OFFSET_ISOC_TX_CH 0x0200 |
111 | #define TSCM_OFFSET_UNKNOWN 0x0204 |
112 | #define TSCM_OFFSET_START_STREAMING 0x0208 |
113 | #define TSCM_OFFSET_ISOC_RX_CH 0x020c |
114 | #define TSCM_OFFSET_ISOC_RX_ON 0x0210 /* Little conviction. */ |
115 | #define TSCM_OFFSET_TX_PCM_CHANNELS 0x0214 |
116 | #define TSCM_OFFSET_RX_PCM_CHANNELS 0x0218 |
117 | #define TSCM_OFFSET_MULTIPLEX_MODE 0x021c |
118 | #define TSCM_OFFSET_ISOC_TX_ON 0x0220 |
119 | /* Unknown 0x0224 */ |
120 | #define TSCM_OFFSET_CLOCK_STATUS 0x0228 |
121 | #define TSCM_OFFSET_SET_OPTION 0x022c |
122 | |
123 | #define TSCM_OFFSET_MIDI_TX_ON 0x0300 |
124 | #define TSCM_OFFSET_MIDI_TX_ADDR_HI 0x0304 |
125 | #define TSCM_OFFSET_MIDI_TX_ADDR_LO 0x0308 |
126 | |
127 | #define TSCM_OFFSET_LED_POWER 0x0404 |
128 | |
129 | #define TSCM_OFFSET_MIDI_RX_QUAD 0x4000 |
130 | |
131 | // Although FE-8 supports the above registers, it has no I/O interfaces for |
132 | // audio samples and music messages. Otherwise it supports another notification |
133 | // for status and control message as well as LED brightening. The message |
134 | // consists of quadlet-aligned data up to 32 quadlets. The first byte of message |
135 | // is fixed to 0x40. The second byte is between 0x00 to 0x1f and represent each |
136 | // control: |
137 | // fader: 0x00-0x07 |
138 | // button: 0x0d, 0x0e |
139 | // knob: 0x14-0x1b |
140 | // sensing: 0x0b |
141 | // |
142 | // The rest two bytes represent state of the controls; e.g. current value for |
143 | // fader and knob, bitmasks for button and sensing. |
144 | // Just after turning on, 32 quadlets messages with 0x00-0x1f are immediately |
145 | // sent in one transaction. After, several quadlets are sent in one transaction. |
146 | // |
147 | // TSCM_OFFSET_FE8_CTL_TX_ON 0x0310 |
148 | // TSCM_OFFSET_FE8_CTL_TX_ADDR_HI 0x0314 |
149 | // TSCM_OFFSET_FE8_CTL_TX_ADDR_LO 0x0318 |
150 | |
151 | enum snd_tscm_clock { |
152 | SND_TSCM_CLOCK_INTERNAL = 0, |
153 | SND_TSCM_CLOCK_WORD = 1, |
154 | SND_TSCM_CLOCK_SPDIF = 2, |
155 | SND_TSCM_CLOCK_ADAT = 3, |
156 | }; |
157 | |
158 | int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, |
159 | enum amdtp_stream_direction dir, unsigned int pcm_channels); |
160 | int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate); |
161 | int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s, |
162 | struct snd_pcm_runtime *runtime); |
163 | |
164 | int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate); |
165 | int snd_tscm_stream_get_clock(struct snd_tscm *tscm, |
166 | enum snd_tscm_clock *clock); |
167 | int snd_tscm_stream_init_duplex(struct snd_tscm *tscm); |
168 | void snd_tscm_stream_update_duplex(struct snd_tscm *tscm); |
169 | void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm); |
170 | int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, |
171 | unsigned int frames_per_period, |
172 | unsigned int frames_per_buffer); |
173 | int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate); |
174 | void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm); |
175 | |
176 | void snd_tscm_stream_lock_changed(struct snd_tscm *tscm); |
177 | int snd_tscm_stream_lock_try(struct snd_tscm *tscm); |
178 | void snd_tscm_stream_lock_release(struct snd_tscm *tscm); |
179 | |
180 | void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port); |
181 | |
182 | static inline void |
183 | snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port, |
184 | struct snd_rawmidi_substream *substream) |
185 | { |
186 | if (!port->error) { |
187 | port->substream = substream; |
188 | schedule_work(work: &port->work); |
189 | } |
190 | } |
191 | |
192 | static inline void |
193 | snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port) |
194 | { |
195 | port->substream = NULL; |
196 | cancel_work_sync(work: &port->work); |
197 | port->error = false; |
198 | } |
199 | |
200 | int snd_tscm_transaction_register(struct snd_tscm *tscm); |
201 | int snd_tscm_transaction_reregister(struct snd_tscm *tscm); |
202 | void snd_tscm_transaction_unregister(struct snd_tscm *tscm); |
203 | |
204 | void snd_tscm_proc_init(struct snd_tscm *tscm); |
205 | |
206 | int snd_tscm_create_pcm_devices(struct snd_tscm *tscm); |
207 | |
208 | int snd_tscm_create_midi_devices(struct snd_tscm *tscm); |
209 | |
210 | int snd_tscm_create_hwdep_device(struct snd_tscm *tscm); |
211 | |
212 | #endif |
213 | |