aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-04-25 09:44:59 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-26 08:23:13 -0400
commit1017abed18ae7087e7f3e256c48421d09d83176e (patch)
treeb98d0848986364dd5bede66b9553da96a60fcfa1 /sound/firewire
parent00a7bb81c20f3e81711e28e0f6c08cee8fd18514 (diff)
ALSA: firewire-lib: Add some AV/C general commands
This commit adds three commands, which may be used by some firewire device drivers. These commands are defined in 'AV/C Digital Interface Command Set General Specification Version 4.2 (2004006, 1394TA)'. 1. PLUG INFO command (clause 10.1) 2. INPUT PLUG SIGNAL FORMAT command (clause 10.10) 3. OUTPUT PLUG SIGNAL FORMAT command (clause 10.11) By the command 1, the drivers can get the number of plugs for AV/C unit or subunit. By the command 2 and 3, the drivers can get/set sampling frequency. The 'firewire-speakers' already uses INPUT PLUG SIGNAL FORMAT command to set sampling rate. So this commit also affects the driver. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/amdtp.c24
-rw-r--r--sound/firewire/amdtp.h1
-rw-r--r--sound/firewire/fcp.c154
-rw-r--r--sound/firewire/fcp.h21
-rw-r--r--sound/firewire/speakers.c43
5 files changed, 194 insertions, 49 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 7c814ace9e58..5b8846123474 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -105,6 +105,17 @@ const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = {
105}; 105};
106EXPORT_SYMBOL(amdtp_syt_intervals); 106EXPORT_SYMBOL(amdtp_syt_intervals);
107 107
108const unsigned int amdtp_rate_table[] = {
109 [CIP_SFC_32000] = 32000,
110 [CIP_SFC_44100] = 44100,
111 [CIP_SFC_48000] = 48000,
112 [CIP_SFC_88200] = 88200,
113 [CIP_SFC_96000] = 96000,
114 [CIP_SFC_176400] = 176400,
115 [CIP_SFC_192000] = 192000,
116};
117EXPORT_SYMBOL(amdtp_rate_table);
118
108/** 119/**
109 * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream 120 * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
110 * @s: the AMDTP stream, which must be initialized. 121 * @s: the AMDTP stream, which must be initialized.
@@ -176,15 +187,6 @@ void amdtp_stream_set_parameters(struct amdtp_stream *s,
176 unsigned int pcm_channels, 187 unsigned int pcm_channels,
177 unsigned int midi_ports) 188 unsigned int midi_ports)
178{ 189{
179 static const unsigned int rates[] = {
180 [CIP_SFC_32000] = 32000,
181 [CIP_SFC_44100] = 44100,
182 [CIP_SFC_48000] = 48000,
183 [CIP_SFC_88200] = 88200,
184 [CIP_SFC_96000] = 96000,
185 [CIP_SFC_176400] = 176400,
186 [CIP_SFC_192000] = 192000,
187 };
188 unsigned int i, sfc, midi_channels; 190 unsigned int i, sfc, midi_channels;
189 191
190 midi_channels = DIV_ROUND_UP(midi_ports, 8); 192 midi_channels = DIV_ROUND_UP(midi_ports, 8);
@@ -194,8 +196,8 @@ void amdtp_stream_set_parameters(struct amdtp_stream *s,
194 WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI)) 196 WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI))
195 return; 197 return;
196 198
197 for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc) 199 for (sfc = 0; sfc < sizeof(amdtp_rate_table); ++sfc)
198 if (rates[sfc] == rate) 200 if (amdtp_rate_table[sfc] == rate)
199 goto sfc_found; 201 goto sfc_found;
200 WARN_ON(1); 202 WARN_ON(1);
201 return; 203 return;
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index d6bb7eb86f0f..3de34639b1c7 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -140,6 +140,7 @@ unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
140void amdtp_stream_pcm_abort(struct amdtp_stream *s); 140void amdtp_stream_pcm_abort(struct amdtp_stream *s);
141 141
142extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT]; 142extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT];
143extern const unsigned int amdtp_rate_table[CIP_SFC_COUNT];
143 144
144/** 145/**
145 * amdtp_stream_running - check stream is running or not 146 * amdtp_stream_running - check stream is running or not
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c
index 6876bfa9f27d..d48e326567c8 100644
--- a/sound/firewire/fcp.c
+++ b/sound/firewire/fcp.c
@@ -10,12 +10,14 @@
10#include <linux/firewire-constants.h> 10#include <linux/firewire-constants.h>
11#include <linux/list.h> 11#include <linux/list.h>
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/slab.h>
13#include <linux/sched.h> 14#include <linux/sched.h>
14#include <linux/spinlock.h> 15#include <linux/spinlock.h>
15#include <linux/wait.h> 16#include <linux/wait.h>
16#include <linux/delay.h> 17#include <linux/delay.h>
17#include "fcp.h" 18#include "fcp.h"
18#include "lib.h" 19#include "lib.h"
20#include "amdtp.h"
19 21
20#define CTS_AVC 0x00 22#define CTS_AVC 0x00
21 23
@@ -23,6 +25,158 @@
23#define ERROR_DELAY_MS 5 25#define ERROR_DELAY_MS 5
24#define FCP_TIMEOUT_MS 125 26#define FCP_TIMEOUT_MS 125
25 27
28int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate,
29 enum avc_general_plug_dir dir,
30 unsigned short pid)
31{
32 unsigned int sfc;
33 u8 *buf;
34 bool flag;
35 int err;
36
37 flag = false;
38 for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {
39 if (amdtp_rate_table[sfc] == rate) {
40 flag = true;
41 break;
42 }
43 }
44 if (!flag)
45 return -EINVAL;
46
47 buf = kzalloc(8, GFP_KERNEL);
48 if (buf == NULL)
49 return -ENOMEM;
50
51 buf[0] = 0x00; /* AV/C CONTROL */
52 buf[1] = 0xff; /* UNIT */
53 if (dir == AVC_GENERAL_PLUG_DIR_IN)
54 buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
55 else
56 buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */
57 buf[3] = 0xff & pid; /* plug id */
58 buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */
59 buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */
60 buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used)*/
61 buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */
62
63 /* do transaction and check buf[1-5] are the same against command */
64 err = fcp_avc_transaction(unit, buf, 8, buf, 8,
65 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
66 if (err >= 0 && err < 8)
67 err = -EIO;
68 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
69 err = -ENOSYS;
70 else if (buf[0] == 0x0a) /* REJECTED */
71 err = -EINVAL;
72 if (err < 0)
73 goto end;
74
75 err = 0;
76end:
77 kfree(buf);
78 return err;
79}
80EXPORT_SYMBOL(avc_general_set_sig_fmt);
81
82int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate,
83 enum avc_general_plug_dir dir,
84 unsigned short pid)
85{
86 unsigned int sfc;
87 u8 *buf;
88 int err;
89
90 buf = kzalloc(8, GFP_KERNEL);
91 if (buf == NULL)
92 return -ENOMEM;
93
94 buf[0] = 0x01; /* AV/C STATUS */
95 buf[1] = 0xff; /* Unit */
96 if (dir == AVC_GENERAL_PLUG_DIR_IN)
97 buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
98 else
99 buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */
100 buf[3] = 0xff & pid; /* plug id */
101 buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */
102 buf[5] = 0xff; /* FDF-hi. AM824, frequency */
103 buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */
104 buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */
105
106 /* do transaction and check buf[1-4] are the same against command */
107 err = fcp_avc_transaction(unit, buf, 8, buf, 8,
108 BIT(1) | BIT(2) | BIT(3) | BIT(4));
109 if (err >= 0 && err < 8)
110 err = -EIO;
111 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
112 err = -ENOSYS;
113 else if (buf[0] == 0x0a) /* REJECTED */
114 err = -EINVAL;
115 else if (buf[0] == 0x0b) /* IN TRANSITION */
116 err = -EAGAIN;
117 if (err < 0)
118 goto end;
119
120 /* check sfc field and pick up rate */
121 sfc = 0x07 & buf[5];
122 if (sfc >= CIP_SFC_COUNT) {
123 err = -EAGAIN; /* also in transition */
124 goto end;
125 }
126
127 *rate = amdtp_rate_table[sfc];
128 err = 0;
129end:
130 kfree(buf);
131 return err;
132}
133EXPORT_SYMBOL(avc_general_get_sig_fmt);
134
135int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type,
136 unsigned int subunit_id, unsigned int subfunction,
137 u8 info[AVC_PLUG_INFO_BUF_BYTES])
138{
139 u8 *buf;
140 int err;
141
142 /* extended subunit in spec.4.2 is not supported */
143 if ((subunit_type == 0x1E) || (subunit_id == 5))
144 return -EINVAL;
145
146 buf = kzalloc(8, GFP_KERNEL);
147 if (buf == NULL)
148 return -ENOMEM;
149
150 buf[0] = 0x01; /* AV/C STATUS */
151 /* UNIT or Subunit, Functionblock */
152 buf[1] = ((subunit_type & 0x1f) << 3) | (subunit_id & 0x7);
153 buf[2] = 0x02; /* PLUG INFO */
154 buf[3] = 0xff & subfunction;
155
156 err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2));
157 if (err >= 0 && err < 8)
158 err = -EIO;
159 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
160 err = -ENOSYS;
161 else if (buf[0] == 0x0a) /* REJECTED */
162 err = -EINVAL;
163 else if (buf[0] == 0x0b) /* IN TRANSITION */
164 err = -EAGAIN;
165 if (err < 0)
166 goto end;
167
168 info[0] = buf[4];
169 info[1] = buf[5];
170 info[2] = buf[6];
171 info[3] = buf[7];
172
173 err = 0;
174end:
175 kfree(buf);
176 return err;
177}
178EXPORT_SYMBOL(avc_general_get_plug_info);
179
26static DEFINE_SPINLOCK(transactions_lock); 180static DEFINE_SPINLOCK(transactions_lock);
27static LIST_HEAD(transactions); 181static LIST_HEAD(transactions);
28 182
diff --git a/sound/firewire/fcp.h b/sound/firewire/fcp.h
index 86595688bd91..63ae4f7ce3af 100644
--- a/sound/firewire/fcp.h
+++ b/sound/firewire/fcp.h
@@ -1,8 +1,29 @@
1#ifndef SOUND_FIREWIRE_FCP_H_INCLUDED 1#ifndef SOUND_FIREWIRE_FCP_H_INCLUDED
2#define SOUND_FIREWIRE_FCP_H_INCLUDED 2#define SOUND_FIREWIRE_FCP_H_INCLUDED
3 3
4#define AVC_PLUG_INFO_BUF_BYTES 4
5
4struct fw_unit; 6struct fw_unit;
5 7
8/*
9 * AV/C Digital Interface Command Set General Specification 4.2
10 * (Sep 2004, 1394TA)
11 */
12enum avc_general_plug_dir {
13 AVC_GENERAL_PLUG_DIR_IN = 0,
14 AVC_GENERAL_PLUG_DIR_OUT = 1,
15 AVC_GENERAL_PLUG_DIR_COUNT
16};
17int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate,
18 enum avc_general_plug_dir dir,
19 unsigned short plug);
20int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate,
21 enum avc_general_plug_dir dir,
22 unsigned short plug);
23int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type,
24 unsigned int subunit_id, unsigned int subfunction,
25 u8 info[AVC_PLUG_INFO_BUF_BYTES]);
26
6int fcp_avc_transaction(struct fw_unit *unit, 27int fcp_avc_transaction(struct fw_unit *unit,
7 const void *command, unsigned int command_size, 28 const void *command, unsigned int command_size,
8 void *response, unsigned int response_size, 29 void *response, unsigned int response_size,
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index dd9983b98607..768d40ddfebb 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -187,42 +187,6 @@ static void fwspk_stop_stream(struct fwspk *fwspk)
187 } 187 }
188} 188}
189 189
190static int fwspk_set_rate(struct fwspk *fwspk, unsigned int sfc)
191{
192 u8 *buf;
193 int err;
194
195 buf = kmalloc(8, GFP_KERNEL);
196 if (!buf)
197 return -ENOMEM;
198
199 buf[0] = 0x00; /* AV/C, CONTROL */
200 buf[1] = 0xff; /* unit */
201 buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
202 buf[3] = 0x00; /* plug 0 */
203 buf[4] = 0x90; /* format: audio */
204 buf[5] = 0x00 | sfc; /* AM824, frequency */
205 buf[6] = 0xff; /* SYT (not used) */
206 buf[7] = 0xff;
207
208 err = fcp_avc_transaction(fwspk->unit, buf, 8, buf, 8,
209 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
210 if (err < 0)
211 goto error;
212 if (err < 6 || buf[0] != 0x09 /* ACCEPTED */) {
213 dev_err(&fwspk->unit->device, "failed to set sample rate\n");
214 err = -EIO;
215 goto error;
216 }
217
218 err = 0;
219
220error:
221 kfree(buf);
222
223 return err;
224}
225
226static int fwspk_hw_params(struct snd_pcm_substream *substream, 190static int fwspk_hw_params(struct snd_pcm_substream *substream,
227 struct snd_pcm_hw_params *hw_params) 191 struct snd_pcm_hw_params *hw_params)
228{ 192{
@@ -246,9 +210,12 @@ static int fwspk_hw_params(struct snd_pcm_substream *substream,
246 amdtp_stream_set_pcm_format(&fwspk->stream, 210 amdtp_stream_set_pcm_format(&fwspk->stream,
247 params_format(hw_params)); 211 params_format(hw_params));
248 212
249 err = fwspk_set_rate(fwspk, fwspk->stream.sfc); 213 err = avc_general_set_sig_fmt(fwspk->unit, params_rate(hw_params),
250 if (err < 0) 214 AVC_GENERAL_PLUG_DIR_IN, 0);
215 if (err < 0) {
216 dev_err(&fwspk->unit->device, "failed to set sample rate\n");
251 goto err_buffer; 217 goto err_buffer;
218 }
252 219
253 return 0; 220 return 0;
254 221