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 | ||
7c2d4c0c | 8 | #include "dice.h" |
82fbb4f7 CL |
9 | |
10 | MODULE_DESCRIPTION("DICE driver"); | |
11 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | |
12 | MODULE_LICENSE("GPL v2"); | |
13 | ||
a471fcde | 14 | #define OUI_WEISS 0x001c6a |
5d5563b1 | 15 | #define OUI_LOUD 0x000ff2 |
a471fcde CL |
16 | |
17 | #define DICE_CATEGORY_ID 0x04 | |
18 | #define WEISS_CATEGORY_ID 0x00 | |
5d5563b1 | 19 | #define LOUD_CATEGORY_ID 0x10 |
cbab328d | 20 | |
b59fb190 TS |
21 | #define PROBE_DELAY_MS (2 * MSEC_PER_SEC) |
22 | ||
4a47a87d | 23 | static int check_dice_category(struct fw_unit *unit) |
cbab328d | 24 | { |
cbab328d CL |
25 | struct fw_device *device = fw_parent_device(unit); |
26 | struct fw_csr_iterator it; | |
4a47a87d TS |
27 | int key, val, vendor = -1, model = -1; |
28 | unsigned int category; | |
7c2d4c0c | 29 | |
cbab328d CL |
30 | /* |
31 | * Check that GUID and unit directory are constructed according to DICE | |
32 | * rules, i.e., that the specifier ID is the GUID's OUI, and that the | |
a471fcde CL |
33 | * GUID chip ID consists of the 8-bit category ID, the 10-bit product |
34 | * ID, and a 22-bit serial number. | |
cbab328d CL |
35 | */ |
36 | fw_csr_iterator_init(&it, unit->directory); | |
7c2d4c0c | 37 | while (fw_csr_iterator_next(&it, &key, &val)) { |
cbab328d CL |
38 | switch (key) { |
39 | case CSR_SPECIFIER_ID: | |
7c2d4c0c | 40 | vendor = val; |
cbab328d CL |
41 | break; |
42 | case CSR_MODEL: | |
7c2d4c0c | 43 | model = val; |
cbab328d CL |
44 | break; |
45 | } | |
46 | } | |
a471fcde CL |
47 | if (vendor == OUI_WEISS) |
48 | category = WEISS_CATEGORY_ID; | |
5d5563b1 TS |
49 | else if (vendor == OUI_LOUD) |
50 | category = LOUD_CATEGORY_ID; | |
a471fcde CL |
51 | else |
52 | category = DICE_CATEGORY_ID; | |
53 | if (device->config_rom[3] != ((vendor << 8) | category) || | |
4a47a87d TS |
54 | device->config_rom[4] >> 22 != model) |
55 | return -ENODEV; | |
cbab328d | 56 | |
4a47a87d | 57 | return 0; |
cbab328d CL |
58 | } |
59 | ||
6eb6c81e TS |
60 | static int highest_supported_mode_rate(struct snd_dice *dice, |
61 | unsigned int mode, unsigned int *rate) | |
15a75c8b | 62 | { |
6eb6c81e | 63 | unsigned int i, m; |
15a75c8b | 64 | |
6eb6c81e TS |
65 | for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) { |
66 | *rate = snd_dice_rates[i - 1]; | |
67 | if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0) | |
68 | continue; | |
69 | if (mode == m) | |
70 | break; | |
71 | } | |
72 | if (i == 0) | |
73 | return -EINVAL; | |
15a75c8b | 74 | |
6eb6c81e | 75 | return 0; |
15a75c8b CL |
76 | } |
77 | ||
732d153f | 78 | static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) |
15a75c8b CL |
79 | { |
80 | __be32 values[2]; | |
6eb6c81e TS |
81 | unsigned int rate; |
82 | int err; | |
15a75c8b | 83 | |
6eb6c81e | 84 | if (highest_supported_mode_rate(dice, mode, &rate) < 0) { |
9a02843c TS |
85 | dice->tx_channels[mode] = 0; |
86 | dice->tx_midi_ports[mode] = 0; | |
15a75c8b CL |
87 | dice->rx_channels[mode] = 0; |
88 | dice->rx_midi_ports[mode] = 0; | |
89 | return 0; | |
90 | } | |
91 | ||
6eb6c81e | 92 | err = snd_dice_transaction_set_rate(dice, rate); |
15a75c8b CL |
93 | if (err < 0) |
94 | return err; | |
95 | ||
9a02843c TS |
96 | err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO, |
97 | values, sizeof(values)); | |
98 | if (err < 0) | |
99 | return err; | |
100 | ||
101 | dice->tx_channels[mode] = be32_to_cpu(values[0]); | |
102 | dice->tx_midi_ports[mode] = be32_to_cpu(values[1]); | |
103 | ||
7c2d4c0c TS |
104 | err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO, |
105 | values, sizeof(values)); | |
15a75c8b CL |
106 | if (err < 0) |
107 | return err; | |
108 | ||
109 | dice->rx_channels[mode] = be32_to_cpu(values[0]); | |
110 | dice->rx_midi_ports[mode] = be32_to_cpu(values[1]); | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
732d153f | 115 | static int dice_read_params(struct snd_dice *dice) |
82fbb4f7 | 116 | { |
a0301998 | 117 | __be32 value; |
15a75c8b | 118 | int mode, err; |
82fbb4f7 | 119 | |
a0301998 | 120 | /* some very old firmwares don't tell about their clock support */ |
7c2d4c0c TS |
121 | if (dice->clock_caps > 0) { |
122 | err = snd_dice_transaction_read_global(dice, | |
123 | GLOBAL_CLOCK_CAPABILITIES, | |
124 | &value, 4); | |
a0301998 CL |
125 | if (err < 0) |
126 | return err; | |
127 | dice->clock_caps = be32_to_cpu(value); | |
128 | } else { | |
129 | /* this should be supported by any device */ | |
130 | dice->clock_caps = CLOCK_CAP_RATE_44100 | | |
131 | CLOCK_CAP_RATE_48000 | | |
132 | CLOCK_CAP_SOURCE_ARX1 | | |
133 | CLOCK_CAP_SOURCE_INTERNAL; | |
134 | } | |
135 | ||
15a75c8b CL |
136 | for (mode = 2; mode >= 0; --mode) { |
137 | err = dice_read_mode_params(dice, mode); | |
138 | if (err < 0) | |
139 | return err; | |
140 | } | |
141 | ||
82fbb4f7 CL |
142 | return 0; |
143 | } | |
144 | ||
732d153f | 145 | static void dice_card_strings(struct snd_dice *dice) |
82fbb4f7 CL |
146 | { |
147 | struct snd_card *card = dice->card; | |
148 | struct fw_device *dev = fw_parent_device(dice->unit); | |
149 | char vendor[32], model[32]; | |
150 | unsigned int i; | |
151 | int err; | |
152 | ||
153 | strcpy(card->driver, "DICE"); | |
154 | ||
155 | strcpy(card->shortname, "DICE"); | |
156 | BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); | |
7c2d4c0c TS |
157 | err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME, |
158 | card->shortname, | |
159 | sizeof(card->shortname)); | |
82fbb4f7 CL |
160 | if (err >= 0) { |
161 | /* DICE strings are returned in "always-wrong" endianness */ | |
162 | BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); | |
163 | for (i = 0; i < sizeof(card->shortname); i += 4) | |
164 | swab32s((u32 *)&card->shortname[i]); | |
165 | card->shortname[sizeof(card->shortname) - 1] = '\0'; | |
166 | } | |
167 | ||
168 | strcpy(vendor, "?"); | |
169 | fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); | |
170 | strcpy(model, "?"); | |
171 | fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); | |
172 | snprintf(card->longname, sizeof(card->longname), | |
cbab328d CL |
173 | "%s %s (serial %u) at %s, S%d", |
174 | vendor, model, dev->config_rom[4] & 0x3fffff, | |
82fbb4f7 CL |
175 | dev_name(&dice->unit->device), 100 << dev->max_speed); |
176 | ||
177 | strcpy(card->mixername, "DICE"); | |
178 | } | |
179 | ||
b59fb190 TS |
180 | static void dice_free(struct snd_dice *dice) |
181 | { | |
182 | snd_dice_stream_destroy_duplex(dice); | |
183 | snd_dice_transaction_destroy(dice); | |
184 | fw_unit_put(dice->unit); | |
185 | ||
186 | mutex_destroy(&dice->mutex); | |
187 | kfree(dice); | |
188 | } | |
189 | ||
12ed7192 TS |
190 | /* |
191 | * This module releases the FireWire unit data after all ALSA character devices | |
192 | * are released by applications. This is for releasing stream data or finishing | |
193 | * transactions safely. Thus at returning from .remove(), this module still keep | |
194 | * references for the unit. | |
195 | */ | |
7c2d4c0c TS |
196 | static void dice_card_free(struct snd_card *card) |
197 | { | |
b59fb190 | 198 | dice_free(card->private_data); |
7c2d4c0c TS |
199 | } |
200 | ||
b59fb190 | 201 | static void do_registration(struct work_struct *work) |
82fbb4f7 | 202 | { |
b59fb190 | 203 | struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work); |
82fbb4f7 CL |
204 | int err; |
205 | ||
b59fb190 TS |
206 | if (dice->registered) |
207 | return; | |
cbab328d | 208 | |
b59fb190 TS |
209 | err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0, |
210 | &dice->card); | |
82fbb4f7 | 211 | if (err < 0) |
b59fb190 | 212 | return; |
82fbb4f7 | 213 | |
7c2d4c0c | 214 | err = snd_dice_transaction_init(dice); |
82fbb4f7 | 215 | if (err < 0) |
7c2d4c0c | 216 | goto error; |
5ea4018e CL |
217 | |
218 | err = dice_read_params(dice); | |
219 | if (err < 0) | |
7c2d4c0c | 220 | goto error; |
82fbb4f7 CL |
221 | |
222 | dice_card_strings(dice); | |
223 | ||
b59fb190 TS |
224 | snd_dice_create_proc(dice); |
225 | ||
c50fb91f | 226 | err = snd_dice_create_pcm(dice); |
82fbb4f7 CL |
227 | if (err < 0) |
228 | goto error; | |
229 | ||
b59fb190 | 230 | err = snd_dice_create_midi(dice); |
82fbb4f7 CL |
231 | if (err < 0) |
232 | goto error; | |
233 | ||
b59fb190 | 234 | err = snd_dice_create_hwdep(dice); |
a113ff88 TS |
235 | if (err < 0) |
236 | goto error; | |
237 | ||
b59fb190 | 238 | err = snd_card_register(dice->card); |
82fbb4f7 CL |
239 | if (err < 0) |
240 | goto error; | |
82fbb4f7 | 241 | |
b59fb190 TS |
242 | /* |
243 | * After registered, dice instance can be released corresponding to | |
244 | * releasing the sound card instance. | |
245 | */ | |
246 | dice->card->private_free = dice_card_free; | |
247 | dice->card->private_data = dice; | |
248 | dice->registered = true; | |
249 | ||
250 | return; | |
251 | error: | |
252 | snd_dice_transaction_destroy(dice); | |
253 | snd_card_free(dice->card); | |
254 | dev_info(&dice->unit->device, | |
255 | "Sound card registration failed: %d\n", err); | |
256 | } | |
257 | ||
258 | static void schedule_registration(struct snd_dice *dice) | |
259 | { | |
260 | struct fw_card *fw_card = fw_parent_device(dice->unit)->card; | |
261 | u64 now, delay; | |
262 | ||
263 | now = get_jiffies_64(); | |
264 | delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS); | |
265 | ||
266 | if (time_after64(delay, now)) | |
267 | delay -= now; | |
268 | else | |
269 | delay = 0; | |
270 | ||
271 | mod_delayed_work(system_wq, &dice->dwork, delay); | |
272 | } | |
273 | ||
274 | static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) | |
275 | { | |
276 | struct snd_dice *dice; | |
277 | int err; | |
278 | ||
279 | err = check_dice_category(unit); | |
280 | if (err < 0) | |
281 | return -ENODEV; | |
282 | ||
283 | /* Allocate this independent of sound card instance. */ | |
284 | dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); | |
285 | if (dice == NULL) | |
286 | return -ENOMEM; | |
287 | ||
288 | dice->unit = fw_unit_get(unit); | |
289 | dev_set_drvdata(&unit->device, dice); | |
290 | ||
291 | spin_lock_init(&dice->lock); | |
292 | mutex_init(&dice->mutex); | |
293 | init_completion(&dice->clock_accepted); | |
294 | init_waitqueue_head(&dice->hwdep_wait); | |
295 | ||
296 | err = snd_dice_stream_init_duplex(dice); | |
7c2d4c0c | 297 | if (err < 0) { |
b59fb190 TS |
298 | dice_free(dice); |
299 | return err; | |
7c2d4c0c | 300 | } |
82fbb4f7 | 301 | |
b59fb190 TS |
302 | /* Allocate and register this sound card later. */ |
303 | INIT_DEFERRABLE_WORK(&dice->dwork, do_registration); | |
304 | schedule_registration(dice); | |
305 | ||
306 | return 0; | |
82fbb4f7 CL |
307 | } |
308 | ||
309 | static void dice_remove(struct fw_unit *unit) | |
310 | { | |
732d153f | 311 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
82fbb4f7 | 312 | |
b59fb190 TS |
313 | /* |
314 | * Confirm to stop the work for registration before the sound card is | |
315 | * going to be released. The work is not scheduled again because bus | |
316 | * reset handler is not called anymore. | |
317 | */ | |
318 | cancel_delayed_work_sync(&dice->dwork); | |
319 | ||
320 | if (dice->registered) { | |
321 | /* No need to wait for releasing card object in this context. */ | |
322 | snd_card_free_when_closed(dice->card); | |
323 | } else { | |
324 | /* Don't forget this case. */ | |
325 | dice_free(dice); | |
326 | } | |
82fbb4f7 CL |
327 | } |
328 | ||
329 | static void dice_bus_reset(struct fw_unit *unit) | |
330 | { | |
732d153f | 331 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
82fbb4f7 | 332 | |
b59fb190 TS |
333 | /* Postpone a workqueue for deferred registration. */ |
334 | if (!dice->registered) | |
335 | schedule_registration(dice); | |
336 | ||
7c2d4c0c TS |
337 | /* The handler address register becomes initialized. */ |
338 | snd_dice_transaction_reinit(dice); | |
339 | ||
b59fb190 TS |
340 | /* |
341 | * After registration, userspace can start packet streaming, then this | |
342 | * code block works fine. | |
343 | */ | |
344 | if (dice->registered) { | |
345 | mutex_lock(&dice->mutex); | |
346 | snd_dice_stream_update_duplex(dice); | |
347 | mutex_unlock(&dice->mutex); | |
348 | } | |
82fbb4f7 CL |
349 | } |
350 | ||
82fbb4f7 CL |
351 | #define DICE_INTERFACE 0x000001 |
352 | ||
353 | static const struct ieee1394_device_id dice_id_table[] = { | |
354 | { | |
cbab328d CL |
355 | .match_flags = IEEE1394_MATCH_VERSION, |
356 | .version = DICE_INTERFACE, | |
82fbb4f7 CL |
357 | }, |
358 | { } | |
359 | }; | |
360 | MODULE_DEVICE_TABLE(ieee1394, dice_id_table); | |
361 | ||
362 | static struct fw_driver dice_driver = { | |
363 | .driver = { | |
364 | .owner = THIS_MODULE, | |
365 | .name = KBUILD_MODNAME, | |
366 | .bus = &fw_bus_type, | |
367 | }, | |
368 | .probe = dice_probe, | |
369 | .update = dice_bus_reset, | |
370 | .remove = dice_remove, | |
371 | .id_table = dice_id_table, | |
372 | }; | |
373 | ||
374 | static int __init alsa_dice_init(void) | |
375 | { | |
376 | return driver_register(&dice_driver.driver); | |
377 | } | |
378 | ||
379 | static void __exit alsa_dice_exit(void) | |
380 | { | |
381 | driver_unregister(&dice_driver.driver); | |
382 | } | |
383 | ||
384 | module_init(alsa_dice_init); | |
385 | module_exit(alsa_dice_exit); |