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