1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * digi00x.c - a part of driver for Digidesign Digi 002/003 family |
4 | * |
5 | * Copyright (c) 2014-2015 Takashi Sakamoto |
6 | */ |
7 | |
8 | #include "digi00x.h" |
9 | |
10 | MODULE_DESCRIPTION("Digidesign Digi 002/003 family Driver" ); |
11 | MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>" ); |
12 | MODULE_LICENSE("GPL" ); |
13 | |
14 | #define VENDOR_DIGIDESIGN 0x00a07e |
15 | #define MODEL_CONSOLE 0x000001 |
16 | #define MODEL_RACK 0x000002 |
17 | #define SPEC_VERSION 0x000001 |
18 | |
19 | static int name_card(struct snd_dg00x *dg00x) |
20 | { |
21 | struct fw_device *fw_dev = fw_parent_device(dg00x->unit); |
22 | char name[32] = {0}; |
23 | char *model; |
24 | int err; |
25 | |
26 | err = fw_csr_string(directory: dg00x->unit->directory, CSR_MODEL, buf: name, |
27 | size: sizeof(name)); |
28 | if (err < 0) |
29 | return err; |
30 | |
31 | model = skip_spaces(name); |
32 | |
33 | strcpy(p: dg00x->card->driver, q: "Digi00x" ); |
34 | strcpy(p: dg00x->card->shortname, q: model); |
35 | strcpy(p: dg00x->card->mixername, q: model); |
36 | snprintf(buf: dg00x->card->longname, size: sizeof(dg00x->card->longname), |
37 | fmt: "Digidesign %s, GUID %08x%08x at %s, S%d" , model, |
38 | fw_dev->config_rom[3], fw_dev->config_rom[4], |
39 | dev_name(dev: &dg00x->unit->device), 100 << fw_dev->max_speed); |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static void dg00x_card_free(struct snd_card *card) |
45 | { |
46 | struct snd_dg00x *dg00x = card->private_data; |
47 | |
48 | snd_dg00x_stream_destroy_duplex(dg00x); |
49 | snd_dg00x_transaction_unregister(dg00x); |
50 | |
51 | mutex_destroy(lock: &dg00x->mutex); |
52 | fw_unit_put(unit: dg00x->unit); |
53 | } |
54 | |
55 | static int snd_dg00x_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) |
56 | { |
57 | struct snd_card *card; |
58 | struct snd_dg00x *dg00x; |
59 | int err; |
60 | |
61 | err = snd_card_new(parent: &unit->device, idx: -1, NULL, THIS_MODULE, extra_size: sizeof(*dg00x), card_ret: &card); |
62 | if (err < 0) |
63 | return err; |
64 | card->private_free = dg00x_card_free; |
65 | |
66 | dg00x = card->private_data; |
67 | dg00x->unit = fw_unit_get(unit); |
68 | dev_set_drvdata(dev: &unit->device, data: dg00x); |
69 | dg00x->card = card; |
70 | |
71 | mutex_init(&dg00x->mutex); |
72 | spin_lock_init(&dg00x->lock); |
73 | init_waitqueue_head(&dg00x->hwdep_wait); |
74 | |
75 | dg00x->is_console = entry->model_id == MODEL_CONSOLE; |
76 | |
77 | err = name_card(dg00x); |
78 | if (err < 0) |
79 | goto error; |
80 | |
81 | err = snd_dg00x_stream_init_duplex(dg00x); |
82 | if (err < 0) |
83 | goto error; |
84 | |
85 | snd_dg00x_proc_init(dg00x); |
86 | |
87 | err = snd_dg00x_create_pcm_devices(dg00x); |
88 | if (err < 0) |
89 | goto error; |
90 | |
91 | err = snd_dg00x_create_midi_devices(dg00x); |
92 | if (err < 0) |
93 | goto error; |
94 | |
95 | err = snd_dg00x_create_hwdep_device(dg00x); |
96 | if (err < 0) |
97 | goto error; |
98 | |
99 | err = snd_dg00x_transaction_register(dg00x); |
100 | if (err < 0) |
101 | goto error; |
102 | |
103 | err = snd_card_register(card); |
104 | if (err < 0) |
105 | goto error; |
106 | |
107 | return 0; |
108 | error: |
109 | snd_card_free(card); |
110 | return err; |
111 | } |
112 | |
113 | static void snd_dg00x_update(struct fw_unit *unit) |
114 | { |
115 | struct snd_dg00x *dg00x = dev_get_drvdata(dev: &unit->device); |
116 | |
117 | snd_dg00x_transaction_reregister(dg00x); |
118 | |
119 | mutex_lock(&dg00x->mutex); |
120 | snd_dg00x_stream_update_duplex(dg00x); |
121 | mutex_unlock(lock: &dg00x->mutex); |
122 | } |
123 | |
124 | static void snd_dg00x_remove(struct fw_unit *unit) |
125 | { |
126 | struct snd_dg00x *dg00x = dev_get_drvdata(dev: &unit->device); |
127 | |
128 | // Block till all of ALSA character devices are released. |
129 | snd_card_free(card: dg00x->card); |
130 | } |
131 | |
132 | static const struct ieee1394_device_id snd_dg00x_id_table[] = { |
133 | /* Both of 002/003 use the same ID. */ |
134 | { |
135 | .match_flags = IEEE1394_MATCH_VENDOR_ID | |
136 | IEEE1394_MATCH_VERSION | |
137 | IEEE1394_MATCH_MODEL_ID, |
138 | .vendor_id = VENDOR_DIGIDESIGN, |
139 | .version = SPEC_VERSION, |
140 | .model_id = MODEL_CONSOLE, |
141 | }, |
142 | { |
143 | .match_flags = IEEE1394_MATCH_VENDOR_ID | |
144 | IEEE1394_MATCH_VERSION | |
145 | IEEE1394_MATCH_MODEL_ID, |
146 | .vendor_id = VENDOR_DIGIDESIGN, |
147 | .version = SPEC_VERSION, |
148 | .model_id = MODEL_RACK, |
149 | }, |
150 | {} |
151 | }; |
152 | MODULE_DEVICE_TABLE(ieee1394, snd_dg00x_id_table); |
153 | |
154 | static struct fw_driver dg00x_driver = { |
155 | .driver = { |
156 | .owner = THIS_MODULE, |
157 | .name = KBUILD_MODNAME, |
158 | .bus = &fw_bus_type, |
159 | }, |
160 | .probe = snd_dg00x_probe, |
161 | .update = snd_dg00x_update, |
162 | .remove = snd_dg00x_remove, |
163 | .id_table = snd_dg00x_id_table, |
164 | }; |
165 | |
166 | static int __init snd_dg00x_init(void) |
167 | { |
168 | return driver_register(drv: &dg00x_driver.driver); |
169 | } |
170 | |
171 | static void __exit snd_dg00x_exit(void) |
172 | { |
173 | driver_unregister(drv: &dg00x_driver.driver); |
174 | } |
175 | |
176 | module_init(snd_dg00x_init); |
177 | module_exit(snd_dg00x_exit); |
178 | |