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 | ||
7c2d4c0c TS |
229 | static void dice_card_free(struct snd_card *card) |
230 | { | |
231 | struct snd_dice *dice = card->private_data; | |
232 | ||
233 | snd_dice_transaction_destroy(dice); | |
234 | mutex_destroy(&dice->mutex); | |
235 | } | |
236 | ||
82fbb4f7 CL |
237 | static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) |
238 | { | |
239 | struct snd_card *card; | |
732d153f | 240 | struct snd_dice *dice; |
82fbb4f7 CL |
241 | int err; |
242 | ||
cbab328d CL |
243 | err = dice_interface_check(unit); |
244 | if (err < 0) | |
7c2d4c0c | 245 | goto end; |
cbab328d | 246 | |
06b45f00 TI |
247 | err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, |
248 | sizeof(*dice), &card); | |
82fbb4f7 | 249 | if (err < 0) |
7c2d4c0c | 250 | goto end; |
82fbb4f7 CL |
251 | |
252 | dice = card->private_data; | |
253 | dice->card = card; | |
7c2d4c0c TS |
254 | dice->unit = unit; |
255 | card->private_free = dice_card_free; | |
256 | ||
0c29c918 | 257 | spin_lock_init(&dice->lock); |
82fbb4f7 | 258 | mutex_init(&dice->mutex); |
15a75c8b | 259 | init_completion(&dice->clock_accepted); |
0c29c918 | 260 | init_waitqueue_head(&dice->hwdep_wait); |
82fbb4f7 | 261 | |
7c2d4c0c | 262 | err = snd_dice_transaction_init(dice); |
82fbb4f7 | 263 | if (err < 0) |
7c2d4c0c | 264 | goto error; |
5ea4018e CL |
265 | |
266 | err = dice_read_params(dice); | |
267 | if (err < 0) | |
7c2d4c0c | 268 | goto error; |
82fbb4f7 CL |
269 | |
270 | dice_card_strings(dice); | |
271 | ||
c50fb91f | 272 | err = snd_dice_create_pcm(dice); |
82fbb4f7 CL |
273 | if (err < 0) |
274 | goto error; | |
275 | ||
19af57b4 | 276 | err = snd_dice_create_hwdep(dice); |
82fbb4f7 CL |
277 | if (err < 0) |
278 | goto error; | |
279 | ||
04d426a0 | 280 | snd_dice_create_proc(dice); |
c614475b | 281 | |
9a02843c | 282 | err = snd_dice_stream_init_duplex(dice); |
82fbb4f7 CL |
283 | if (err < 0) |
284 | goto error; | |
82fbb4f7 | 285 | |
7c2d4c0c TS |
286 | err = snd_card_register(card); |
287 | if (err < 0) { | |
9a02843c | 288 | snd_dice_stream_destroy_duplex(dice); |
7c2d4c0c TS |
289 | goto error; |
290 | } | |
82fbb4f7 | 291 | |
7c2d4c0c TS |
292 | dev_set_drvdata(&unit->device, dice); |
293 | end: | |
294 | return err; | |
82fbb4f7 CL |
295 | error: |
296 | snd_card_free(card); | |
297 | return err; | |
298 | } | |
299 | ||
300 | static void dice_remove(struct fw_unit *unit) | |
301 | { | |
732d153f | 302 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
82fbb4f7 | 303 | |
4ed31f20 CL |
304 | snd_card_disconnect(dice->card); |
305 | ||
9a02843c | 306 | snd_dice_stream_destroy_duplex(dice); |
4ed31f20 | 307 | |
82fbb4f7 CL |
308 | snd_card_free_when_closed(dice->card); |
309 | } | |
310 | ||
311 | static void dice_bus_reset(struct fw_unit *unit) | |
312 | { | |
732d153f | 313 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
82fbb4f7 | 314 | |
7c2d4c0c TS |
315 | /* The handler address register becomes initialized. */ |
316 | snd_dice_transaction_reinit(dice); | |
317 | ||
a8c558f6 | 318 | mutex_lock(&dice->mutex); |
9a02843c | 319 | snd_dice_stream_update_duplex(dice); |
82fbb4f7 CL |
320 | mutex_unlock(&dice->mutex); |
321 | } | |
322 | ||
82fbb4f7 CL |
323 | #define DICE_INTERFACE 0x000001 |
324 | ||
325 | static const struct ieee1394_device_id dice_id_table[] = { | |
326 | { | |
cbab328d CL |
327 | .match_flags = IEEE1394_MATCH_VERSION, |
328 | .version = DICE_INTERFACE, | |
82fbb4f7 CL |
329 | }, |
330 | { } | |
331 | }; | |
332 | MODULE_DEVICE_TABLE(ieee1394, dice_id_table); | |
333 | ||
334 | static struct fw_driver dice_driver = { | |
335 | .driver = { | |
336 | .owner = THIS_MODULE, | |
337 | .name = KBUILD_MODNAME, | |
338 | .bus = &fw_bus_type, | |
339 | }, | |
340 | .probe = dice_probe, | |
341 | .update = dice_bus_reset, | |
342 | .remove = dice_remove, | |
343 | .id_table = dice_id_table, | |
344 | }; | |
345 | ||
346 | static int __init alsa_dice_init(void) | |
347 | { | |
348 | return driver_register(&dice_driver.driver); | |
349 | } | |
350 | ||
351 | static void __exit alsa_dice_exit(void) | |
352 | { | |
353 | driver_unregister(&dice_driver.driver); | |
354 | } | |
355 | ||
356 | module_init(alsa_dice_init); | |
357 | module_exit(alsa_dice_exit); |