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