1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5 #include <assert.h>
6 #include <libudev.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <regex.h>
15 #include <syslog.h>
16
17 #include "cras_system_state.h"
18 #include "cras_types.h"
19 #include "cras_util.h"
20 #include "cras_checksum.h"
21
22 struct udev_callback_data {
23 struct udev_monitor *mon;
24 struct udev *udev;
25 int fd;
26 };
27
28 static unsigned is_action(const char *desired,
29 const char *actual) __attribute__((nonnull(1)));
30
31 /* Matches Alsa sound device entries generated by udev. For
32 * example:
33 *
34 * /devices/pci0000:00/0000:00:1b.0/sound/card1/pcmC1D0p
35 *
36 * We want to be able to extract:
37 *
38 * o The card number
39 * o The device number
40 * o If it's 'playback' (p) or 'capture' (c). (It may not be both.)
41 *
42 * Given the example above, the following matches should occur:
43 *
44 *
45 * | A |
46 * BBCCCD
47 * /devices/pci0000:00/0000:00:1b.0/sound/card1/pcmC1D10p
48 *
49 * A: The whole regex will be matched.
50 * B: The card.
51 * C: The device.
52 * D: 'p' (playback) or 'c' (capture)
53 *
54 * The order of the offsets in the 'pmatch' buffer does not appear
55 * to match with the documentation:
56 *
57 * Each rm_so element that is not -1 indicates the start
58 * offset of the next largest substring match within the
59 * string.
60 *
61 * But are, instead, filled in the same order presented in the
62 * string. To alleviate possible issudes, the 'C' (card) and 'D'
63 * (device) identifying characters are included in the result.
64 */
65 static const char pcm_regex_string[] = "^.*pcm(C[0-9]+)(D[0-9]+)([pc])";
66 static regex_t pcm_regex;
67
68 /* Card regex is similar to above, but only has one field -- the card. The
69 * format is the same with the exception of the leaf node being of the form:
70 *
71 * /devices/...../card0
72 *
73 * Where 0 is the card number and the only thing we care about in
74 * this case.
75 */
76
77 static const char card_regex_string[] = "^.*/card([0-9]+)";
78 static regex_t card_regex;
79
80 static char const * const subsystem = "sound";
81 static const unsigned int MAX_DESC_NAME_LEN = 256;
82
is_action(const char * desired,const char * actual)83 static unsigned is_action(const char *desired, const char *actual)
84 {
85 return actual != NULL && strcmp(desired, actual) == 0;
86 }
87
is_action_change(const char * action)88 static unsigned is_action_change(const char *action)
89 {
90 return is_action("change", action);
91 }
92
is_action_remove(const char * action)93 static unsigned is_action_remove(const char *action)
94 {
95 return is_action("remove", action);
96 }
97
is_internal_bus(const char * bus)98 static unsigned is_internal_bus(const char *bus)
99 {
100 return (bus != NULL &&
101 (strcmp(bus, "pci") == 0 ||
102 strcmp(bus, "platform") == 0));
103 }
104
is_external_bus(const char * bus)105 static unsigned is_external_bus(const char *bus)
106 {
107 return (bus != NULL && (strcmp(bus, "usb") == 0));
108 }
109
is_internal_device(struct udev_device * dev)110 static unsigned is_internal_device(struct udev_device *dev)
111 {
112 struct udev_device *parent = udev_device_get_parent(dev);
113 while (parent != NULL) {
114 const char *name = udev_device_get_subsystem(parent);
115
116 if (name != NULL) {
117 if (is_external_bus(name))
118 return 0;
119 else if (is_internal_bus(name))
120 return 1;
121 }
122 parent = udev_device_get_parent(parent);
123 }
124 return 0;
125 }
126
is_card_device(struct udev_device * dev,unsigned * internal,unsigned * card_number,const char ** sysname)127 static unsigned is_card_device(struct udev_device *dev,
128 unsigned *internal,
129 unsigned *card_number,
130 const char **sysname)
131 {
132 regmatch_t m[2];
133 const char *devpath = udev_device_get_devpath(dev);
134
135 if (devpath != NULL &&
136 regexec(&card_regex, devpath, ARRAY_SIZE(m), m, 0) == 0) {
137 *sysname = udev_device_get_sysname(dev);
138 *internal = is_internal_device(dev);
139 *card_number = (unsigned)atoi(&devpath[m[1].rm_so]);
140 return 1;
141 }
142
143 return 0;
144 }
145
set_factory_default(unsigned card_number)146 static void set_factory_default(unsigned card_number)
147 {
148 static const char alsactl[] = "/usr/sbin/alsactl";
149 static const char asound_state[] = "/etc/asound.state";
150 char cmd_buf[128];
151 struct stat stat_buf;
152 int r;
153
154 if (stat(asound_state, &stat_buf) == 0) {
155 syslog(LOG_INFO, "%s: init card '%u' to factory default",
156 __FUNCTION__, card_number);
157 r = snprintf(cmd_buf, ARRAY_SIZE(cmd_buf),
158 "%s --file %s restore %u",
159 alsactl, asound_state, card_number);
160 cmd_buf[ARRAY_SIZE(cmd_buf) - 1] = '\0';
161 r = system(cmd_buf);
162 if (r != 0)
163 syslog(LOG_ERR,
164 "%s: failed to init card '%d' "
165 "to factory default. Failure: %d. Command: %s",
166 __FUNCTION__, card_number, r, cmd_buf);
167 }
168 }
169
udev_delay_for_alsa()170 static inline void udev_delay_for_alsa()
171 {
172 /* Provide a small delay so that the udev message can
173 * propogate throughout the whole system, and Alsa can set up
174 * the new device. Without a small delay, an error of the
175 * form:
176 *
177 * Fail opening control hw:?
178 *
179 * will be produced by cras_alsa_card_create().
180 */
181 usleep(125000); /* 0.125 second */
182 }
183
184 /* Reads the "descriptors" file of the usb device and returns the
185 * checksum of the contents. Returns 0 if the file can not be read */
calculate_desc_checksum(struct udev_device * dev)186 static uint32_t calculate_desc_checksum(struct udev_device *dev)
187 {
188 char path[MAX_DESC_NAME_LEN];
189 struct stat stat_buf;
190 int fd;
191 unsigned char *buf = NULL;
192 int buf_size = 0;
193 int read_size;
194 ssize_t n;
195 uint32_t result;
196
197 if (snprintf(path, sizeof(path), "%s/descriptors",
198 udev_device_get_syspath(dev)) >= sizeof(path)) {
199 syslog(LOG_ERR, "failed to build path");
200 return 0;
201 }
202
203 if (stat(path, &stat_buf) < 0) {
204 syslog(LOG_ERR, "failed to stat file %s: %s",
205 path, strerror(errno));
206 return 0;
207 }
208
209 fd = open(path, O_RDONLY);
210 if (fd < 0) {
211 syslog(LOG_ERR, "failed to open file %s: %s",
212 path, strerror(errno));
213 return 0;
214 }
215
216 read_size = 0;
217 while (read_size < stat_buf.st_size) {
218 if (read_size == buf_size) {
219 if (buf_size == 0)
220 buf_size = 256;
221 else
222 buf_size *= 2;
223 uint8_t *new_buf = realloc(buf, buf_size);
224 if (new_buf == NULL) {
225 syslog(LOG_ERR,
226 "no memory to read file %s", path);
227 goto bail;
228 }
229 buf = new_buf;
230 }
231 n = read(fd, buf + read_size, buf_size - read_size);
232 if (n == 0)
233 break;
234 if (n < 0) {
235 syslog(LOG_ERR, "failed to read file %s", path);
236 goto bail;
237 }
238 read_size += n;
239 }
240
241 close(fd);
242 result = crc32_checksum(buf, read_size);
243 free(buf);
244 return result;
245 bail:
246 close(fd);
247 free(buf);
248 return 0;
249 }
250
fill_usb_card_info(struct cras_alsa_card_info * card_info,struct udev_device * dev)251 static void fill_usb_card_info(struct cras_alsa_card_info *card_info,
252 struct udev_device *dev)
253 {
254 const char *sysattr;
255 struct udev_device *parent_dev =
256 udev_device_get_parent_with_subsystem_devtype(dev,
257 "usb",
258 "usb_device");
259 if (!parent_dev)
260 return;
261
262 sysattr = udev_device_get_sysattr_value(parent_dev, "idVendor");
263 if (sysattr)
264 card_info->usb_vendor_id = strtol(sysattr, NULL, 16);
265 sysattr = udev_device_get_sysattr_value(parent_dev, "idProduct");
266 if (sysattr)
267 card_info->usb_product_id = strtol(sysattr, NULL, 16);
268 sysattr = udev_device_get_sysattr_value(parent_dev, "serial");
269 if (sysattr) {
270 strncpy(card_info->usb_serial_number, sysattr,
271 USB_SERIAL_NUMBER_BUFFER_SIZE - 1);
272 card_info->usb_serial_number[USB_SERIAL_NUMBER_BUFFER_SIZE - 1]
273 = '\0';
274 }
275
276 card_info->usb_desc_checksum = calculate_desc_checksum(parent_dev);
277
278 syslog(LOG_ERR, "USB card: vendor:%04x, product:%04x, serial num:%s, "
279 "checksum:%08x",
280 card_info->usb_vendor_id, card_info->usb_product_id,
281 card_info->usb_serial_number, card_info->usb_desc_checksum);
282 }
283
device_add_alsa(struct udev_device * dev,const char * sysname,unsigned card,unsigned internal)284 static void device_add_alsa(struct udev_device *dev,
285 const char *sysname,
286 unsigned card,
287 unsigned internal)
288 {
289 struct cras_alsa_card_info card_info;
290 memset(&card_info, 0, sizeof(card_info));
291
292 udev_delay_for_alsa();
293 card_info.card_index = card;
294 if (internal) {
295 card_info.card_type = ALSA_CARD_TYPE_INTERNAL;
296 } else {
297 card_info.card_type = ALSA_CARD_TYPE_USB;
298 fill_usb_card_info(&card_info, dev);
299 }
300
301 cras_system_add_alsa_card(&card_info);
302 }
303
device_remove_alsa(const char * sysname,unsigned card)304 void device_remove_alsa(const char *sysname, unsigned card)
305 {
306 udev_delay_for_alsa();
307 cras_system_remove_alsa_card(card);
308 }
309
udev_sound_initialized(struct udev_device * dev)310 static int udev_sound_initialized(struct udev_device *dev)
311 {
312 /* udev will set SOUND_INITALIZED=1 for the main card node when the
313 * system has already been initialized, i.e. when cras is restarted
314 * on an already running system.
315 */
316 const char *s;
317
318 s = udev_device_get_property_value(dev, "SOUND_INITIALIZED");
319 if (s)
320 return 1;
321
322 return 0;
323 }
324
change_udev_device_if_alsa_device(struct udev_device * dev)325 static void change_udev_device_if_alsa_device(struct udev_device *dev)
326 {
327 /* If the device, 'dev' is an alsa device, add it to the set of
328 * devices available for I/O. Mark it as the active device.
329 */
330 unsigned internal;
331 unsigned card_number;
332 const char *sysname;
333
334 if (is_card_device(dev, &internal, &card_number, &sysname) &&
335 udev_sound_initialized(dev) &&
336 !cras_system_alsa_card_exists(card_number)) {
337 if (internal)
338 set_factory_default(card_number);
339 device_add_alsa(dev, sysname, card_number, internal);
340 }
341 }
342
remove_device_if_card(struct udev_device * dev)343 static void remove_device_if_card(struct udev_device *dev)
344 {
345 unsigned internal;
346 unsigned card_number;
347 const char *sysname;
348
349 if (is_card_device(dev, &internal, &card_number, &sysname))
350 device_remove_alsa(sysname, card_number);
351 }
352
enumerate_devices(struct udev_callback_data * data)353 static void enumerate_devices(struct udev_callback_data *data)
354 {
355 struct udev_enumerate *enumerate = udev_enumerate_new(data->udev);
356 struct udev_list_entry *dl;
357 struct udev_list_entry *dev_list_entry;
358
359 udev_enumerate_add_match_subsystem(enumerate, subsystem);
360 udev_enumerate_scan_devices(enumerate);
361 dl = udev_enumerate_get_list_entry(enumerate);
362
363 udev_list_entry_foreach(dev_list_entry, dl) {
364 const char *path = udev_list_entry_get_name(dev_list_entry);
365 struct udev_device *dev =
366 udev_device_new_from_syspath(data->udev, path);
367
368 change_udev_device_if_alsa_device(dev);
369 udev_device_unref(dev);
370 }
371 udev_enumerate_unref(enumerate);
372 }
373
udev_sound_subsystem_callback(void * arg)374 static void udev_sound_subsystem_callback(void *arg)
375 {
376 struct udev_callback_data *data = (struct udev_callback_data *)arg;
377 struct udev_device *dev;
378
379 dev = udev_monitor_receive_device(data->mon);
380 if (dev) {
381 const char *action = udev_device_get_action(dev);
382
383 if (is_action_change(action))
384 change_udev_device_if_alsa_device(dev);
385 else if (is_action_remove(action))
386 remove_device_if_card(dev);
387 udev_device_unref(dev);
388 } else
389 syslog(LOG_WARNING,
390 "%s (internal error): "
391 "No device obtained", __FUNCTION__);
392 }
393
compile_regex(regex_t * regex,const char * str)394 static void compile_regex(regex_t *regex, const char *str)
395 {
396 int r = regcomp(regex, str, REG_EXTENDED);
397 assert(r == 0);
398 }
399
400 static struct udev_callback_data udev_data;
cras_udev_start_sound_subsystem_monitor()401 void cras_udev_start_sound_subsystem_monitor()
402 {
403 int r;
404
405 udev_data.udev = udev_new();
406 assert(udev_data.udev != NULL);
407 udev_data.mon = udev_monitor_new_from_netlink(udev_data.udev, "udev");
408
409 udev_monitor_filter_add_match_subsystem_devtype(udev_data.mon,
410 subsystem, NULL);
411 udev_monitor_enable_receiving(udev_data.mon);
412 udev_data.fd = udev_monitor_get_fd(udev_data.mon);
413
414 r = cras_system_add_select_fd(udev_data.fd,
415 udev_sound_subsystem_callback,
416 &udev_data);
417 assert(r == 0);
418 compile_regex(&pcm_regex, pcm_regex_string);
419 compile_regex(&card_regex, card_regex_string);
420
421 enumerate_devices(&udev_data);
422 }
423
cras_udev_stop_sound_subsystem_monitor()424 void cras_udev_stop_sound_subsystem_monitor()
425 {
426 udev_unref(udev_data.udev);
427 regfree(&pcm_regex);
428 regfree(&card_regex);
429 }
430