Commit | Line | Data |
---|---|---|
82fbb4f7 CL |
1 | /* |
2 | * TC Applied Technologies Digital Interface Communications Engine driver | |
3 | * | |
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | |
5 | * Licensed under the terms of the GNU General Public License, version 2. | |
6 | */ | |
7 | ||
8 | #include <linux/delay.h> | |
9 | #include <linux/device.h> | |
10 | #include <linux/firewire.h> | |
11 | #include <linux/firewire-constants.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/mod_devicetable.h> | |
14 | #include <linux/mutex.h> | |
15 | #include <linux/slab.h> | |
16 | #include <sound/control.h> | |
17 | #include <sound/core.h> | |
18 | #include <sound/hwdep.h> | |
19 | #include <sound/initval.h> | |
20 | #include <sound/pcm.h> | |
21 | #include <sound/pcm_params.h> | |
22 | #include "amdtp.h" | |
23 | #include "iso-resources.h" | |
24 | #include "lib.h" | |
25 | ||
26 | #define DICE_PRIVATE_SPACE 0xffffe0000000uLL | |
27 | ||
28 | /* offset from DICE_PRIVATE_SPACE; offsets and sizes in quadlets */ | |
29 | #define DICE_GLOBAL_OFFSET 0x00 | |
30 | #define DICE_GLOBAL_SIZE 0x04 | |
31 | #define DICE_TX_OFFSET 0x08 | |
32 | #define DICE_TX_SIZE 0x0c | |
33 | #define DICE_RX_OFFSET 0x10 | |
34 | #define DICE_RX_SIZE 0x14 | |
35 | ||
36 | /* pointed to by DICE_GLOBAL_OFFSET */ | |
37 | #define GLOBAL_OWNER 0x000 | |
38 | #define OWNER_NO_OWNER 0xffff000000000000uLL | |
39 | #define OWNER_NODE_SHIFT 48 | |
40 | #define GLOBAL_NOTIFICATION 0x008 | |
41 | #define NOTIFY_RX_CFG_CHG 0x00000001 | |
42 | #define NOTIFY_TX_CFG_CHG 0x00000002 | |
43 | #define NOTIFY_DUP_ISOC 0x00000004 | |
44 | #define NOTIFY_BW_ERR 0x00000008 | |
45 | #define NOTIFY_LOCK_CHG 0x00000010 | |
46 | #define NOTIFY_CLOCK_ACCEPTED 0x00000020 | |
47 | #define NOTIFY_INTERFACE_CHG 0x00000040 | |
48 | #define NOTIFY_MESSAGE 0x00100000 | |
49 | #define GLOBAL_NICK_NAME 0x00c | |
50 | #define NICK_NAME_SIZE 64 | |
51 | #define GLOBAL_CLOCK_SELECT 0x04c | |
52 | #define CLOCK_SOURCE_MASK 0x000000ff | |
53 | #define CLOCK_SOURCE_AES1 0x00000000 | |
54 | #define CLOCK_SOURCE_AES2 0x00000001 | |
55 | #define CLOCK_SOURCE_AES3 0x00000002 | |
56 | #define CLOCK_SOURCE_AES4 0x00000003 | |
57 | #define CLOCK_SOURCE_AES_ANY 0x00000004 | |
58 | #define CLOCK_SOURCE_ADAT 0x00000005 | |
59 | #define CLOCK_SOURCE_TDIF 0x00000006 | |
60 | #define CLOCK_SOURCE_WC 0x00000007 | |
61 | #define CLOCK_SOURCE_ARX1 0x00000008 | |
62 | #define CLOCK_SOURCE_ARX2 0x00000009 | |
63 | #define CLOCK_SOURCE_ARX3 0x0000000a | |
64 | #define CLOCK_SOURCE_ARX4 0x0000000b | |
65 | #define CLOCK_SOURCE_INTERNAL 0x0000000c | |
66 | #define CLOCK_RATE_MASK 0x0000ff00 | |
67 | #define CLOCK_RATE_32000 0x00000000 | |
68 | #define CLOCK_RATE_44100 0x00000100 | |
69 | #define CLOCK_RATE_48000 0x00000200 | |
70 | #define CLOCK_RATE_88200 0x00000300 | |
71 | #define CLOCK_RATE_96000 0x00000400 | |
72 | #define CLOCK_RATE_176400 0x00000500 | |
73 | #define CLOCK_RATE_192000 0x00000600 | |
74 | #define CLOCK_RATE_ANY_LOW 0x00000700 | |
75 | #define CLOCK_RATE_ANY_MID 0x00000800 | |
76 | #define CLOCK_RATE_ANY_HIGH 0x00000900 | |
77 | #define CLOCK_RATE_NONE 0x00000a00 | |
78 | #define GLOBAL_ENABLE 0x050 | |
79 | #define ENABLE 0x00000001 | |
80 | #define GLOBAL_STATUS 0x054 | |
81 | #define STATUS_SOURCE_LOCKED 0x00000001 | |
82 | #define STATUS_RATE_CONFLICT 0x00000002 | |
83 | #define STATUS_NOMINAL_RATE_MASK 0x0000ff00 | |
84 | #define GLOBAL_EXTENDED_STATUS 0x058 | |
85 | #define EXT_STATUS_AES1_LOCKED 0x00000001 | |
86 | #define EXT_STATUS_AES2_LOCKED 0x00000002 | |
87 | #define EXT_STATUS_AES3_LOCKED 0x00000004 | |
88 | #define EXT_STATUS_AES4_LOCKED 0x00000008 | |
89 | #define EXT_STATUS_ADAT_LOCKED 0x00000010 | |
90 | #define EXT_STATUS_TDIF_LOCKED 0x00000020 | |
91 | #define EXT_STATUS_ARX1_LOCKED 0x00000040 | |
92 | #define EXT_STATUS_ARX2_LOCKED 0x00000080 | |
93 | #define EXT_STATUS_ARX3_LOCKED 0x00000100 | |
94 | #define EXT_STATUS_ARX4_LOCKED 0x00000200 | |
95 | #define EXT_STATUS_WC_LOCKED 0x00000400 | |
96 | #define EXT_STATUS_AES1_SLIP 0x00010000 | |
97 | #define EXT_STATUS_AES2_SLIP 0x00020000 | |
98 | #define EXT_STATUS_AES3_SLIP 0x00040000 | |
99 | #define EXT_STATUS_AES4_SLIP 0x00080000 | |
100 | #define EXT_STATUS_ADAT_SLIP 0x00100000 | |
101 | #define EXT_STATUS_TDIF_SLIP 0x00200000 | |
102 | #define EXT_STATUS_ARX1_SLIP 0x00400000 | |
103 | #define EXT_STATUS_ARX2_SLIP 0x00800000 | |
104 | #define EXT_STATUS_ARX3_SLIP 0x01000000 | |
105 | #define EXT_STATUS_ARX4_SLIP 0x02000000 | |
106 | #define EXT_STATUS_WC_SLIP 0x04000000 | |
107 | #define GLOBAL_SAMPLE_RATE 0x05c | |
108 | #define GLOBAL_VERSION 0x060 | |
109 | #define GLOBAL_CLOCK_CAPABILITIES 0x064 | |
110 | #define CLOCK_CAP_RATE_32000 0x00000001 | |
111 | #define CLOCK_CAP_RATE_44100 0x00000002 | |
112 | #define CLOCK_CAP_RATE_48000 0x00000004 | |
113 | #define CLOCK_CAP_RATE_88200 0x00000008 | |
114 | #define CLOCK_CAP_RATE_96000 0x00000010 | |
115 | #define CLOCK_CAP_RATE_176400 0x00000020 | |
116 | #define CLOCK_CAP_RATE_192000 0x00000040 | |
117 | #define CLOCK_CAP_SOURCE_AES1 0x00010000 | |
118 | #define CLOCK_CAP_SOURCE_AES2 0x00020000 | |
119 | #define CLOCK_CAP_SOURCE_AES3 0x00040000 | |
120 | #define CLOCK_CAP_SOURCE_AES4 0x00080000 | |
121 | #define CLOCK_CAP_SOURCE_AES_ANY 0x00100000 | |
122 | #define CLOCK_CAP_SOURCE_ADAT 0x00200000 | |
123 | #define CLOCK_CAP_SOURCE_TDIF 0x00400000 | |
124 | #define CLOCK_CAP_SOURCE_WC 0x00800000 | |
125 | #define CLOCK_CAP_SOURCE_ARX1 0x01000000 | |
126 | #define CLOCK_CAP_SOURCE_ARX2 0x02000000 | |
127 | #define CLOCK_CAP_SOURCE_ARX3 0x04000000 | |
128 | #define CLOCK_CAP_SOURCE_ARX4 0x08000000 | |
129 | #define CLOCK_CAP_SOURCE_INTERNAL 0x10000000 | |
130 | #define GLOBAL_CLOCK_SOURCE_NAMES 0x068 | |
131 | #define CLOCK_SOURCE_NAMES_SIZE 256 | |
132 | ||
133 | /* pointed to by DICE_TX_OFFSET */ | |
134 | #define TX_NUMBER 0x000 | |
135 | #define TX_SIZE 0x004 | |
136 | /* repeated TX_NUMBER times, offset by TX_SIZE quadlets */ | |
137 | #define TX_ISOCHRONOUS 0x008 | |
138 | #define TX_NUMBER_AUDIO 0x00c | |
139 | #define TX_NUMBER_MIDI 0x010 | |
140 | #define TX_SPEED 0x014 | |
141 | #define TX_NAMES 0x018 | |
142 | #define TX_NAMES_SIZE 256 | |
143 | #define TX_AC3_CAPABILITIES 0x118 | |
144 | #define TX_AC3_ENABLE 0x11c | |
145 | ||
146 | /* pointed to by DICE_RX_OFFSET */ | |
147 | #define RX_NUMBER 0x000 | |
148 | #define RX_SIZE 0x004 | |
149 | /* repeated RX_NUMBER times, offset by RX_SIZE quadlets */ | |
150 | #define RX_ISOCHRONOUS 0x008 | |
151 | #define RX_SEQ_START 0x00c | |
152 | #define RX_NUMBER_AUDIO 0x010 | |
153 | #define RX_NUMBER_MIDI 0x014 | |
154 | #define RX_NAMES 0x018 | |
155 | #define RX_NAMES_SIZE 256 | |
156 | #define RX_AC3_CAPABILITIES 0x118 | |
157 | #define RX_AC3_ENABLE 0x11c | |
158 | ||
159 | ||
160 | #define FIRMWARE_LOAD_SPACE 0xffffe0100000uLL | |
161 | ||
162 | /* offset from FIRMWARE_LOAD_SPACE */ | |
163 | #define FIRMWARE_VERSION 0x000 | |
164 | #define FIRMWARE_OPCODE 0x004 | |
165 | #define OPCODE_MASK 0x00000fff | |
166 | #define OPCODE_GET_IMAGE_DESC 0x00000000 | |
167 | #define OPCODE_DELETE_IMAGE 0x00000001 | |
168 | #define OPCODE_CREATE_IMAGE 0x00000002 | |
169 | #define OPCODE_UPLOAD 0x00000003 | |
170 | #define OPCODE_UPLOAD_STAT 0x00000004 | |
171 | #define OPCODE_RESET_IMAGE 0x00000005 | |
172 | #define OPCODE_TEST_ACTION 0x00000006 | |
173 | #define OPCODE_GET_RUNNING_IMAGE_VINFO 0x0000000a | |
174 | #define OPCODE_EXECUTE 0x80000000 | |
175 | #define FIRMWARE_RETURN_STATUS 0x008 | |
176 | #define FIRMWARE_PROGRESS 0x00c | |
177 | #define PROGRESS_CURR_MASK 0x00000fff | |
178 | #define PROGRESS_MAX_MASK 0x00fff000 | |
179 | #define PROGRESS_TOUT_MASK 0x0f000000 | |
180 | #define PROGRESS_FLAG 0x80000000 | |
181 | #define FIRMWARE_CAPABILITIES 0x010 | |
182 | #define FL_CAP_AUTOERASE 0x00000001 | |
183 | #define FL_CAP_PROGRESS 0x00000002 | |
184 | #define FIRMWARE_DATA 0x02c | |
185 | #define TEST_CMD_POKE 0x00000001 | |
186 | #define TEST_CMD_PEEK 0x00000002 | |
187 | #define CMD_GET_AVS_CNT 0x00000003 | |
188 | #define CMD_CLR_AVS_CNT 0x00000004 | |
189 | #define CMD_SET_MODE 0x00000005 | |
190 | #define CMD_SET_MIDIBP 0x00000006 | |
191 | #define CMD_GET_AVSPHASE 0x00000007 | |
192 | #define CMD_ENABLE_BNC_SYNC 0x00000008 | |
193 | #define CMD_PULSE_BNC_SYNC 0x00000009 | |
194 | #define CMD_EMUL_SLOW_CMD 0x0000000a | |
195 | #define FIRMWARE_TEST_DELAY 0xfd8 | |
196 | #define FIRMWARE_TEST_BUF 0xfdc | |
197 | ||
198 | ||
199 | /* EAP */ | |
200 | #define EAP_PRIVATE_SPACE 0xffffe0200000uLL | |
201 | ||
202 | #define EAP_CAPABILITY_OFFSET 0x000 | |
203 | #define EAP_CAPABILITY_SIZE 0x004 | |
204 | /* ... */ | |
205 | ||
206 | #define EAP_ROUTER_CAPS 0x000 | |
207 | #define ROUTER_EXPOSED 0x00000001 | |
208 | #define ROUTER_READ_ONLY 0x00000002 | |
209 | #define ROUTER_FLASH 0x00000004 | |
210 | #define MAX_ROUTES_MASK 0xffff0000 | |
211 | #define EAP_MIXER_CAPS 0x004 | |
212 | #define MIXER_EXPOSED 0x00000001 | |
213 | #define MIXER_READ_ONLY 0x00000002 | |
214 | #define MIXER_FLASH 0x00000004 | |
215 | #define MIXER_IN_DEV_MASK 0x000000f0 | |
216 | #define MIXER_OUT_DEV_MASK 0x00000f00 | |
217 | #define MIXER_INPUTS_MASK 0x00ff0000 | |
218 | #define MIXER_OUTPUTS_MASK 0xff000000 | |
219 | #define EAP_GENERAL_CAPS 0x008 | |
220 | #define GENERAL_STREAM_CONFIG 0x00000001 | |
221 | #define GENERAL_FLASH 0x00000002 | |
222 | #define GENERAL_PEAK 0x00000004 | |
223 | #define GENERAL_MAX_TX_STREAMS_MASK 0x000000f0 | |
224 | #define GENERAL_MAX_RX_STREAMS_MASK 0x00000f00 | |
225 | #define GENERAL_STREAM_CONFIG_FLASH 0x00001000 | |
226 | #define GENERAL_CHIP_MASK 0x00ff0000 | |
227 | #define GENERAL_CHIP_DICE_II 0x00000000 | |
228 | #define GENERAL_CHIP_DICE_MINI 0x00010000 | |
229 | #define GENERAL_CHIP_DICE_JR 0x00020000 | |
230 | ||
231 | ||
232 | struct dice { | |
233 | struct snd_card *card; | |
234 | struct fw_unit *unit; | |
235 | struct mutex mutex; | |
236 | unsigned int global_offset; | |
237 | unsigned int rx_offset; | |
238 | struct fw_address_handler notification_handler; | |
239 | int owner_generation; | |
240 | bool global_enabled; | |
241 | bool stream_running; | |
242 | struct snd_pcm_substream *pcm; | |
243 | struct fw_iso_resources resources; | |
244 | struct amdtp_out_stream stream; | |
245 | }; | |
246 | ||
247 | MODULE_DESCRIPTION("DICE driver"); | |
248 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | |
249 | MODULE_LICENSE("GPL v2"); | |
250 | ||
251 | static inline u64 global_address(struct dice *dice, unsigned int offset) | |
252 | { | |
253 | return DICE_PRIVATE_SPACE + dice->global_offset + offset; | |
254 | } | |
255 | ||
256 | // TODO: rx index | |
257 | static inline u64 rx_address(struct dice *dice, unsigned int offset) | |
258 | { | |
259 | return DICE_PRIVATE_SPACE + dice->rx_offset + offset; | |
260 | } | |
261 | ||
262 | static int dice_owner_set(struct dice *dice) | |
263 | { | |
264 | struct fw_device *device = fw_parent_device(dice->unit); | |
265 | __be64 *buffer; | |
266 | int rcode, err, errors = 0; | |
267 | ||
268 | buffer = kmalloc(2 * 8, GFP_KERNEL); | |
269 | if (!buffer) | |
270 | return -ENOMEM; | |
271 | ||
272 | for (;;) { | |
273 | buffer[0] = cpu_to_be64(OWNER_NO_OWNER); | |
274 | buffer[1] = cpu_to_be64( | |
275 | ((u64)device->card->node_id << OWNER_NODE_SHIFT) | | |
276 | dice->notification_handler.offset); | |
277 | ||
278 | dice->owner_generation = device->generation; | |
279 | smp_rmb(); /* node_id vs. generation */ | |
280 | rcode = fw_run_transaction(device->card, | |
281 | TCODE_LOCK_COMPARE_SWAP, | |
282 | device->node_id, | |
283 | dice->owner_generation, | |
284 | device->max_speed, | |
285 | global_address(dice, GLOBAL_OWNER), | |
286 | buffer, 2 * 8); | |
287 | ||
288 | if (rcode == RCODE_COMPLETE) { | |
289 | if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) { | |
290 | err = 0; | |
291 | } else { | |
292 | dev_err(&dice->unit->device, | |
293 | "device is already in use\n"); | |
294 | err = -EBUSY; | |
295 | } | |
296 | break; | |
297 | } | |
298 | if (rcode_is_permanent_error(rcode) || ++errors >= 3) { | |
299 | dev_err(&dice->unit->device, | |
300 | "setting device owner failed: %s\n", | |
301 | fw_rcode_string(rcode)); | |
302 | err = -EIO; | |
303 | break; | |
304 | } | |
305 | msleep(20); | |
306 | } | |
307 | ||
308 | kfree(buffer); | |
309 | ||
310 | return err; | |
311 | } | |
312 | ||
313 | static int dice_owner_update(struct dice *dice) | |
314 | { | |
315 | struct fw_device *device = fw_parent_device(dice->unit); | |
316 | __be64 *buffer; | |
317 | int rcode, err, errors = 0; | |
318 | ||
319 | if (dice->owner_generation == -1) | |
320 | return 0; | |
321 | ||
322 | buffer = kmalloc(2 * 8, GFP_KERNEL); | |
323 | if (!buffer) | |
324 | return -ENOMEM; | |
325 | ||
326 | for (;;) { | |
327 | buffer[0] = cpu_to_be64(OWNER_NO_OWNER); | |
328 | buffer[1] = cpu_to_be64( | |
329 | ((u64)device->card->node_id << OWNER_NODE_SHIFT) | | |
330 | dice->notification_handler.offset); | |
331 | ||
332 | dice->owner_generation = device->generation; | |
333 | smp_rmb(); /* node_id vs. generation */ | |
334 | rcode = fw_run_transaction(device->card, | |
335 | TCODE_LOCK_COMPARE_SWAP, | |
336 | device->node_id, | |
337 | dice->owner_generation, | |
338 | device->max_speed, | |
339 | global_address(dice, GLOBAL_OWNER), | |
340 | buffer, 2 * 8); | |
341 | ||
342 | if (rcode == RCODE_COMPLETE) { | |
343 | if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) { | |
344 | err = 0; | |
345 | } else { | |
346 | dev_err(&dice->unit->device, | |
347 | "device is already in use\n"); | |
348 | err = -EBUSY; | |
349 | } | |
350 | break; | |
351 | } | |
352 | if (rcode == RCODE_GENERATION) { | |
353 | err = 0; /* try again later */ | |
354 | break; | |
355 | } | |
356 | if (rcode_is_permanent_error(rcode) || ++errors >= 3) { | |
357 | dev_err(&dice->unit->device, | |
358 | "setting device owner failed: %s\n", | |
359 | fw_rcode_string(rcode)); | |
360 | err = -EIO; | |
361 | break; | |
362 | } | |
363 | msleep(20); | |
364 | } | |
365 | ||
366 | kfree(buffer); | |
367 | ||
368 | if (err < 0) | |
369 | dice->owner_generation = -1; | |
370 | ||
371 | return err; | |
372 | } | |
373 | ||
374 | static void dice_owner_clear(struct dice *dice) | |
375 | { | |
376 | struct fw_device *device = fw_parent_device(dice->unit); | |
377 | __be64 *buffer; | |
378 | int rcode, errors = 0; | |
379 | ||
380 | buffer = kmalloc(2 * 8, GFP_KERNEL); | |
381 | if (!buffer) | |
382 | return; | |
383 | ||
384 | for (;;) { | |
385 | buffer[0] = cpu_to_be64( | |
386 | ((u64)device->card->node_id << OWNER_NODE_SHIFT) | | |
387 | dice->notification_handler.offset); | |
388 | buffer[1] = cpu_to_be64(OWNER_NO_OWNER); | |
389 | ||
390 | rcode = fw_run_transaction(device->card, | |
391 | TCODE_LOCK_COMPARE_SWAP, | |
392 | device->node_id, | |
393 | dice->owner_generation, | |
394 | device->max_speed, | |
395 | global_address(dice, GLOBAL_OWNER), | |
396 | buffer, 2 * 8); | |
397 | ||
398 | if (rcode == RCODE_COMPLETE) | |
399 | break; | |
400 | if (rcode == RCODE_GENERATION) | |
401 | break; | |
402 | if (rcode_is_permanent_error(rcode) || ++errors >= 3) { | |
403 | dev_err(&dice->unit->device, | |
404 | "clearing device owner failed: %s\n", | |
405 | fw_rcode_string(rcode)); | |
406 | break; | |
407 | } | |
408 | msleep(20); | |
409 | } | |
410 | ||
411 | kfree(buffer); | |
412 | ||
413 | dice->owner_generation = -1; | |
414 | } | |
415 | ||
416 | static int dice_enable_set(struct dice *dice) | |
417 | { | |
418 | struct fw_device *device = fw_parent_device(dice->unit); | |
419 | __be32 value; | |
420 | int rcode, err, errors = 0; | |
421 | ||
422 | value = cpu_to_be32(ENABLE); | |
423 | for (;;) { | |
424 | rcode = fw_run_transaction(device->card, | |
425 | TCODE_WRITE_QUADLET_REQUEST, | |
426 | device->node_id, | |
427 | dice->owner_generation, | |
428 | device->max_speed, | |
429 | global_address(dice, GLOBAL_ENABLE), | |
430 | &value, 4); | |
431 | if (rcode == RCODE_COMPLETE) { | |
432 | dice->global_enabled = true; | |
433 | err = 0; | |
434 | break; | |
435 | } | |
436 | if (rcode == RCODE_GENERATION) { | |
437 | err = -EAGAIN; | |
438 | break; | |
439 | } | |
440 | if (rcode_is_permanent_error(rcode) || ++errors >= 3) { | |
441 | dev_err(&dice->unit->device, | |
442 | "device enabling failed: %s\n", | |
443 | fw_rcode_string(rcode)); | |
444 | err = -EIO; | |
445 | break; | |
446 | } | |
447 | msleep(20); | |
448 | } | |
449 | ||
450 | return err; | |
451 | } | |
452 | ||
453 | static void dice_enable_clear(struct dice *dice) | |
454 | { | |
455 | struct fw_device *device = fw_parent_device(dice->unit); | |
456 | __be32 value; | |
457 | int rcode, errors = 0; | |
458 | ||
459 | value = 0; | |
460 | for (;;) { | |
461 | rcode = fw_run_transaction(device->card, | |
462 | TCODE_WRITE_QUADLET_REQUEST, | |
463 | device->node_id, | |
464 | dice->owner_generation, | |
465 | device->max_speed, | |
466 | global_address(dice, GLOBAL_ENABLE), | |
467 | &value, 4); | |
468 | if (rcode == RCODE_COMPLETE || | |
469 | rcode == RCODE_GENERATION) | |
470 | break; | |
471 | if (rcode_is_permanent_error(rcode) || ++errors >= 3) { | |
472 | dev_err(&dice->unit->device, | |
473 | "device disabling failed: %s\n", | |
474 | fw_rcode_string(rcode)); | |
475 | break; | |
476 | } | |
477 | msleep(20); | |
478 | } | |
479 | dice->global_enabled = false; | |
480 | } | |
481 | ||
482 | static void dice_notification(struct fw_card *card, struct fw_request *request, | |
483 | int tcode, int destination, int source, | |
484 | int generation, unsigned long long offset, | |
485 | void *data, size_t length, void *callback_data) | |
486 | { | |
487 | struct dice *dice = callback_data; | |
488 | ||
489 | if (tcode != TCODE_WRITE_QUADLET_REQUEST) { | |
490 | fw_send_response(card, request, RCODE_TYPE_ERROR); | |
491 | return; | |
492 | } | |
493 | if ((offset & 3) != 0) { | |
494 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | |
495 | return; | |
496 | } | |
497 | dev_info(&dice->unit->device, | |
498 | "notification: %08x\n", be32_to_cpup(data)); | |
499 | fw_send_response(card, request, RCODE_COMPLETE); | |
500 | } | |
501 | ||
502 | static int dice_open(struct snd_pcm_substream *substream) | |
503 | { | |
504 | static const struct snd_pcm_hardware hardware = { | |
505 | .info = SNDRV_PCM_INFO_MMAP | | |
506 | SNDRV_PCM_INFO_MMAP_VALID | | |
507 | SNDRV_PCM_INFO_BATCH | | |
508 | SNDRV_PCM_INFO_INTERLEAVED | | |
509 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | |
510 | .formats = AMDTP_OUT_PCM_FORMAT_BITS, | |
511 | .rates = SNDRV_PCM_RATE_44100, | |
512 | .rate_min = 44100, | |
513 | .rate_max = 44100, | |
514 | .buffer_bytes_max = 16 * 1024 * 1024, | |
515 | .period_bytes_min = 1, | |
516 | .period_bytes_max = UINT_MAX, | |
517 | .periods_min = 1, | |
518 | .periods_max = UINT_MAX, | |
519 | }; | |
520 | struct dice *dice = substream->private_data; | |
521 | struct snd_pcm_runtime *runtime = substream->runtime; | |
522 | __be32 number_audio, number_midi; | |
523 | int err; | |
524 | ||
525 | err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, | |
526 | rx_address(dice, RX_NUMBER_AUDIO), | |
527 | &number_audio, 4); | |
528 | if (err < 0) | |
529 | return err; | |
530 | err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, | |
531 | rx_address(dice, RX_NUMBER_MIDI), | |
532 | &number_midi, 4); | |
533 | if (err < 0) | |
534 | return err; | |
535 | ||
536 | runtime->hw = hardware; | |
537 | runtime->hw.channels_min = be32_to_cpu(number_audio); | |
538 | runtime->hw.channels_max = be32_to_cpu(number_audio); | |
539 | ||
540 | amdtp_out_stream_set_rate(&dice->stream, 44100); | |
541 | amdtp_out_stream_set_pcm(&dice->stream, be32_to_cpu(number_audio)); | |
542 | amdtp_out_stream_set_midi(&dice->stream, be32_to_cpu(number_midi)); | |
543 | ||
544 | err = snd_pcm_hw_constraint_minmax(runtime, | |
545 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | |
546 | 5000, 8192000); | |
547 | if (err < 0) | |
548 | return err; | |
549 | ||
550 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | |
551 | if (err < 0) | |
552 | return err; | |
553 | ||
554 | return 0; | |
555 | } | |
556 | ||
557 | static int dice_close(struct snd_pcm_substream *substream) | |
558 | { | |
559 | return 0; | |
560 | } | |
561 | ||
6abce9e6 | 562 | static int dice_stream_start_packets(struct dice *dice) |
82fbb4f7 | 563 | { |
6abce9e6 CL |
564 | int err; |
565 | ||
566 | if (dice->stream_running) | |
567 | return 0; | |
82fbb4f7 | 568 | |
6abce9e6 CL |
569 | err = amdtp_out_stream_start(&dice->stream, dice->resources.channel, |
570 | fw_parent_device(dice->unit)->max_speed); | |
571 | if (err < 0) | |
572 | return err; | |
82fbb4f7 | 573 | |
6abce9e6 CL |
574 | err = dice_enable_set(dice); |
575 | if (err < 0) { | |
82fbb4f7 | 576 | amdtp_out_stream_stop(&dice->stream); |
6abce9e6 CL |
577 | return err; |
578 | } | |
82fbb4f7 | 579 | |
6abce9e6 | 580 | dice->stream_running = true; |
82fbb4f7 | 581 | |
6abce9e6 CL |
582 | return 0; |
583 | } | |
82fbb4f7 | 584 | |
6abce9e6 CL |
585 | static int dice_stream_start(struct dice *dice) |
586 | { | |
587 | __be32 channel; | |
588 | int err; | |
589 | ||
590 | if (!dice->resources.allocated) { | |
591 | err = fw_iso_resources_allocate(&dice->resources, | |
592 | amdtp_out_stream_get_max_payload(&dice->stream), | |
593 | fw_parent_device(dice->unit)->max_speed); | |
594 | if (err < 0) | |
595 | goto error; | |
596 | ||
597 | channel = cpu_to_be32(dice->resources.channel); | |
598 | err = snd_fw_transaction(dice->unit, | |
599 | TCODE_WRITE_QUADLET_REQUEST, | |
600 | rx_address(dice, RX_ISOCHRONOUS), | |
601 | &channel, 4); | |
602 | if (err < 0) | |
603 | goto err_resources; | |
82fbb4f7 | 604 | } |
6abce9e6 CL |
605 | |
606 | err = dice_stream_start_packets(dice); | |
607 | if (err < 0) | |
608 | goto err_rx_channel; | |
609 | ||
610 | return 0; | |
611 | ||
612 | err_rx_channel: | |
613 | channel = cpu_to_be32((u32)-1); | |
614 | snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, | |
615 | rx_address(dice, RX_ISOCHRONOUS), &channel, 4); | |
616 | err_resources: | |
617 | fw_iso_resources_free(&dice->resources); | |
618 | error: | |
619 | return err; | |
620 | } | |
621 | ||
622 | static void dice_stream_stop_packets(struct dice *dice) | |
623 | { | |
624 | if (!dice->stream_running) | |
625 | return; | |
626 | ||
627 | dice_enable_clear(dice); | |
628 | ||
629 | amdtp_out_stream_stop(&dice->stream); | |
630 | ||
631 | dice->stream_running = false; | |
632 | } | |
633 | ||
634 | static void dice_stream_stop(struct dice *dice) | |
635 | { | |
636 | __be32 channel; | |
637 | ||
638 | dice_stream_stop_packets(dice); | |
639 | ||
640 | if (!dice->resources.allocated) | |
641 | return; | |
642 | ||
643 | channel = cpu_to_be32((u32)-1); | |
644 | snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, | |
645 | rx_address(dice, RX_ISOCHRONOUS), &channel, 4); | |
646 | ||
647 | fw_iso_resources_free(&dice->resources); | |
82fbb4f7 CL |
648 | } |
649 | ||
650 | static int dice_hw_params(struct snd_pcm_substream *substream, | |
651 | struct snd_pcm_hw_params *hw_params) | |
652 | { | |
653 | struct dice *dice = substream->private_data; | |
654 | int err; | |
655 | ||
656 | mutex_lock(&dice->mutex); | |
6abce9e6 | 657 | dice_stream_stop(dice); |
82fbb4f7 CL |
658 | mutex_unlock(&dice->mutex); |
659 | ||
660 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | |
661 | params_buffer_bytes(hw_params)); | |
662 | if (err < 0) | |
663 | goto error; | |
664 | ||
665 | amdtp_out_stream_set_pcm_format(&dice->stream, | |
666 | params_format(hw_params)); | |
667 | ||
668 | return 0; | |
669 | ||
670 | error: | |
671 | return err; | |
672 | } | |
673 | ||
674 | static int dice_hw_free(struct snd_pcm_substream *substream) | |
675 | { | |
676 | struct dice *dice = substream->private_data; | |
677 | ||
678 | mutex_lock(&dice->mutex); | |
6abce9e6 | 679 | dice_stream_stop(dice); |
82fbb4f7 CL |
680 | mutex_unlock(&dice->mutex); |
681 | ||
682 | return snd_pcm_lib_free_vmalloc_buffer(substream); | |
683 | } | |
684 | ||
685 | static int dice_prepare(struct snd_pcm_substream *substream) | |
686 | { | |
687 | struct dice *dice = substream->private_data; | |
82fbb4f7 CL |
688 | int err; |
689 | ||
690 | mutex_lock(&dice->mutex); | |
691 | ||
692 | if (amdtp_out_streaming_error(&dice->stream)) | |
6abce9e6 | 693 | dice_stream_stop_packets(dice); |
82fbb4f7 | 694 | |
6abce9e6 CL |
695 | err = dice_stream_start(dice); |
696 | if (err < 0) { | |
697 | mutex_unlock(&dice->mutex); | |
698 | return err; | |
82fbb4f7 CL |
699 | } |
700 | ||
701 | mutex_unlock(&dice->mutex); | |
702 | ||
703 | amdtp_out_stream_pcm_prepare(&dice->stream); | |
704 | ||
705 | return 0; | |
82fbb4f7 CL |
706 | } |
707 | ||
708 | static int dice_trigger(struct snd_pcm_substream *substream, int cmd) | |
709 | { | |
710 | struct dice *dice = substream->private_data; | |
711 | struct snd_pcm_substream *pcm; | |
712 | ||
713 | switch (cmd) { | |
714 | case SNDRV_PCM_TRIGGER_START: | |
715 | pcm = substream; | |
716 | break; | |
717 | case SNDRV_PCM_TRIGGER_STOP: | |
718 | pcm = NULL; | |
719 | break; | |
720 | default: | |
721 | return -EINVAL; | |
722 | } | |
723 | amdtp_out_stream_pcm_trigger(&dice->stream, pcm); | |
724 | ||
725 | return 0; | |
726 | } | |
727 | ||
728 | static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) | |
729 | { | |
730 | struct dice *dice = substream->private_data; | |
731 | ||
732 | return amdtp_out_stream_pcm_pointer(&dice->stream); | |
733 | } | |
734 | ||
735 | static int dice_create_pcm(struct dice *dice) | |
736 | { | |
737 | static struct snd_pcm_ops ops = { | |
738 | .open = dice_open, | |
739 | .close = dice_close, | |
740 | .ioctl = snd_pcm_lib_ioctl, | |
741 | .hw_params = dice_hw_params, | |
742 | .hw_free = dice_hw_free, | |
743 | .prepare = dice_prepare, | |
744 | .trigger = dice_trigger, | |
745 | .pointer = dice_pointer, | |
746 | .page = snd_pcm_lib_get_vmalloc_page, | |
747 | .mmap = snd_pcm_lib_mmap_vmalloc, | |
748 | }; | |
749 | __be32 clock; | |
750 | struct snd_pcm *pcm; | |
751 | int err; | |
752 | ||
753 | clock = cpu_to_be32(CLOCK_SOURCE_ARX1 | CLOCK_RATE_44100); | |
754 | err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, | |
755 | global_address(dice, GLOBAL_CLOCK_SELECT), | |
756 | &clock, 4); | |
757 | if (err < 0) | |
758 | return err; | |
759 | ||
760 | err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); | |
761 | if (err < 0) | |
762 | return err; | |
763 | pcm->private_data = dice; | |
764 | strcpy(pcm->name, dice->card->shortname); | |
765 | dice->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | |
766 | dice->pcm->ops = &ops; | |
767 | ||
768 | return 0; | |
769 | } | |
770 | ||
771 | // TODO: implement these | |
772 | ||
773 | static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, | |
774 | long count, loff_t *offset) | |
775 | { | |
776 | return -EIO; | |
777 | } | |
778 | ||
779 | static int dice_hwdep_open(struct snd_hwdep *hwdep, struct file *file) | |
780 | { | |
781 | return -EIO; | |
782 | } | |
783 | ||
784 | static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) | |
785 | { | |
786 | return 0; | |
787 | } | |
788 | ||
789 | static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, | |
790 | poll_table *wait) | |
791 | { | |
792 | return POLLERR | POLLHUP; | |
793 | } | |
794 | ||
795 | static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, | |
796 | unsigned int cmd, unsigned long arg) | |
797 | { | |
798 | return -EIO; | |
799 | } | |
800 | ||
801 | static int dice_create_hwdep(struct dice *dice) | |
802 | { | |
803 | static const struct snd_hwdep_ops ops = { | |
804 | .read = dice_hwdep_read, | |
805 | .open = dice_hwdep_open, | |
806 | .release = dice_hwdep_release, | |
807 | .poll = dice_hwdep_poll, | |
808 | .ioctl = dice_hwdep_ioctl, | |
809 | .ioctl_compat = dice_hwdep_ioctl, | |
810 | }; | |
811 | struct snd_hwdep *hwdep; | |
812 | int err; | |
813 | ||
814 | err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); | |
815 | if (err < 0) | |
816 | return err; | |
817 | strcpy(hwdep->name, "DICE"); | |
818 | hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; | |
819 | hwdep->ops = ops; | |
820 | hwdep->private_data = dice; | |
821 | hwdep->exclusive = true; | |
822 | ||
823 | return 0; | |
824 | } | |
825 | ||
826 | static void dice_card_free(struct snd_card *card) | |
827 | { | |
828 | struct dice *dice = card->private_data; | |
829 | ||
830 | amdtp_out_stream_destroy(&dice->stream); | |
831 | fw_core_remove_address_handler(&dice->notification_handler); | |
832 | mutex_destroy(&dice->mutex); | |
833 | } | |
834 | ||
835 | static int dice_init_offsets(struct dice *dice) | |
836 | { | |
837 | __be32 pointers[6]; | |
838 | unsigned int global_size, rx_size; | |
839 | int err; | |
840 | ||
841 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, | |
842 | DICE_PRIVATE_SPACE, &pointers, 6 * 4); | |
843 | if (err < 0) | |
844 | return err; | |
845 | ||
846 | dice->global_offset = be32_to_cpu(pointers[0]) * 4; | |
847 | global_size = be32_to_cpu(pointers[1]); | |
848 | dice->rx_offset = be32_to_cpu(pointers[4]) * 4; | |
849 | rx_size = be32_to_cpu(pointers[5]); | |
850 | ||
851 | /* some sanity checks to ensure that we actually have a DICE */ | |
852 | if (dice->global_offset < 10 * 4 || global_size < 0x168 / 4 || | |
853 | dice->rx_offset < 10 * 4 || rx_size < 0x120 / 4) { | |
854 | dev_err(&dice->unit->device, "invalid register pointers\n"); | |
855 | return -ENXIO; | |
856 | } | |
857 | ||
858 | return 0; | |
859 | } | |
860 | ||
861 | static void dice_card_strings(struct dice *dice) | |
862 | { | |
863 | struct snd_card *card = dice->card; | |
864 | struct fw_device *dev = fw_parent_device(dice->unit); | |
865 | char vendor[32], model[32]; | |
866 | unsigned int i; | |
867 | int err; | |
868 | ||
869 | strcpy(card->driver, "DICE"); | |
870 | ||
871 | strcpy(card->shortname, "DICE"); | |
872 | BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); | |
873 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, | |
874 | global_address(dice, GLOBAL_NICK_NAME), | |
875 | card->shortname, sizeof(card->shortname)); | |
876 | if (err >= 0) { | |
877 | /* DICE strings are returned in "always-wrong" endianness */ | |
878 | BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); | |
879 | for (i = 0; i < sizeof(card->shortname); i += 4) | |
880 | swab32s((u32 *)&card->shortname[i]); | |
881 | card->shortname[sizeof(card->shortname) - 1] = '\0'; | |
882 | } | |
883 | ||
884 | strcpy(vendor, "?"); | |
885 | fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); | |
886 | strcpy(model, "?"); | |
887 | fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); | |
888 | snprintf(card->longname, sizeof(card->longname), | |
889 | "%s %s, GUID %08x%08x at %s, S%d", | |
890 | vendor, model, dev->config_rom[3], dev->config_rom[4], | |
891 | dev_name(&dice->unit->device), 100 << dev->max_speed); | |
892 | ||
893 | strcpy(card->mixername, "DICE"); | |
894 | } | |
895 | ||
896 | static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) | |
897 | { | |
898 | struct snd_card *card; | |
899 | struct dice *dice; | |
900 | int err; | |
901 | ||
902 | err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card); | |
903 | if (err < 0) | |
904 | return err; | |
905 | snd_card_set_dev(card, &unit->device); | |
906 | ||
907 | dice = card->private_data; | |
908 | dice->card = card; | |
909 | mutex_init(&dice->mutex); | |
910 | dice->unit = unit; | |
911 | ||
912 | err = dice_init_offsets(dice); | |
913 | if (err < 0) | |
914 | goto err_mutex; | |
915 | ||
916 | dice->notification_handler.length = 4; | |
917 | dice->notification_handler.address_callback = dice_notification; | |
918 | dice->notification_handler.callback_data = dice; | |
919 | err = fw_core_add_address_handler(&dice->notification_handler, | |
920 | &fw_high_memory_region); | |
921 | if (err < 0) | |
922 | goto err_mutex; | |
923 | ||
924 | err = fw_iso_resources_init(&dice->resources, unit); | |
925 | if (err < 0) | |
926 | goto err_notification_handler; | |
927 | dice->resources.channels_mask = 0x00000000ffffffffuLL; | |
928 | ||
929 | err = amdtp_out_stream_init(&dice->stream, unit, CIP_NONBLOCKING); | |
930 | if (err < 0) | |
931 | goto err_resources; | |
932 | ||
933 | err = dice_owner_set(dice); | |
934 | if (err < 0) | |
935 | goto err_stream; | |
936 | ||
937 | card->private_free = dice_card_free; | |
938 | ||
939 | dice_card_strings(dice); | |
940 | ||
941 | err = dice_create_pcm(dice); | |
942 | if (err < 0) | |
943 | goto error; | |
944 | ||
945 | err = dice_create_hwdep(dice); | |
946 | if (err < 0) | |
947 | goto error; | |
948 | ||
949 | err = snd_card_register(card); | |
950 | if (err < 0) | |
951 | goto error; | |
952 | ||
953 | dev_set_drvdata(&unit->device, dice); | |
954 | ||
955 | return 0; | |
956 | ||
957 | err_stream: | |
958 | amdtp_out_stream_destroy(&dice->stream); | |
959 | err_resources: | |
960 | fw_iso_resources_destroy(&dice->resources); | |
961 | err_notification_handler: | |
962 | fw_core_remove_address_handler(&dice->notification_handler); | |
963 | err_mutex: | |
964 | mutex_destroy(&dice->mutex); | |
965 | error: | |
966 | snd_card_free(card); | |
967 | return err; | |
968 | } | |
969 | ||
970 | static void dice_remove(struct fw_unit *unit) | |
971 | { | |
972 | struct dice *dice = dev_get_drvdata(&unit->device); | |
973 | ||
974 | snd_card_disconnect(dice->card); | |
975 | ||
976 | mutex_lock(&dice->mutex); | |
977 | amdtp_out_stream_pcm_abort(&dice->stream); | |
6abce9e6 | 978 | dice_stream_stop(dice); |
82fbb4f7 CL |
979 | dice_owner_clear(dice); |
980 | mutex_unlock(&dice->mutex); | |
981 | ||
982 | snd_card_free_when_closed(dice->card); | |
983 | } | |
984 | ||
985 | static void dice_bus_reset(struct fw_unit *unit) | |
986 | { | |
987 | struct dice *dice = dev_get_drvdata(&unit->device); | |
988 | ||
989 | mutex_lock(&dice->mutex); | |
6abce9e6 | 990 | |
82fbb4f7 | 991 | /* |
82fbb4f7 CL |
992 | * On a bus reset, the DICE firmware disables streaming and then goes |
993 | * off contemplating its own navel for hundreds of milliseconds before | |
994 | * it can react to any of our attempts to reenable streaming. This | |
995 | * means that we lose synchronization anyway, so we force our streams | |
996 | * to stop so that the application can restart them in an orderly | |
997 | * manner. | |
998 | */ | |
82fbb4f7 | 999 | amdtp_out_stream_pcm_abort(&dice->stream); |
6abce9e6 CL |
1000 | dice_stream_stop_packets(dice); |
1001 | ||
1002 | dice_owner_update(dice); | |
1003 | ||
1004 | fw_iso_resources_update(&dice->resources); | |
1005 | ||
82fbb4f7 CL |
1006 | mutex_unlock(&dice->mutex); |
1007 | } | |
1008 | ||
1009 | #define TC_OUI 0x000166 | |
1010 | #define DICE_INTERFACE 0x000001 | |
1011 | ||
1012 | static const struct ieee1394_device_id dice_id_table[] = { | |
1013 | { | |
1014 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | | |
1015 | IEEE1394_MATCH_VERSION, | |
1016 | .specifier_id = TC_OUI, | |
1017 | .version = DICE_INTERFACE, | |
1018 | }, | |
1019 | { } | |
1020 | }; | |
1021 | MODULE_DEVICE_TABLE(ieee1394, dice_id_table); | |
1022 | ||
1023 | static struct fw_driver dice_driver = { | |
1024 | .driver = { | |
1025 | .owner = THIS_MODULE, | |
1026 | .name = KBUILD_MODNAME, | |
1027 | .bus = &fw_bus_type, | |
1028 | }, | |
1029 | .probe = dice_probe, | |
1030 | .update = dice_bus_reset, | |
1031 | .remove = dice_remove, | |
1032 | .id_table = dice_id_table, | |
1033 | }; | |
1034 | ||
1035 | static int __init alsa_dice_init(void) | |
1036 | { | |
1037 | return driver_register(&dice_driver.driver); | |
1038 | } | |
1039 | ||
1040 | static void __exit alsa_dice_exit(void) | |
1041 | { | |
1042 | driver_unregister(&dice_driver.driver); | |
1043 | } | |
1044 | ||
1045 | module_init(alsa_dice_init); | |
1046 | module_exit(alsa_dice_exit); |