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, const char *actual)
29 __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 || strcmp(bus, "platform") == 0));
102 }
103
is_external_bus(const char * bus)104 static unsigned is_external_bus(const char *bus)
105 {
106 return (bus != NULL && (strcmp(bus, "usb") == 0));
107 }
108
is_internal_device(struct udev_device * dev)109 static unsigned is_internal_device(struct udev_device *dev)
110 {
111 struct udev_device *parent = udev_device_get_parent(dev);
112 while (parent != NULL) {
113 const char *name = udev_device_get_subsystem(parent);
114
115 if (name != NULL) {
116 if (is_external_bus(name))
117 return 0;
118 else if (is_internal_bus(name))
119 return 1;
120 }
121 parent = udev_device_get_parent(parent);
122 }
123 return 0;
124 }
125
is_card_device(struct udev_device * dev,unsigned * internal,unsigned * card_number,const char ** sysname)126 static unsigned is_card_device(struct udev_device *dev, unsigned *internal,
127 unsigned *card_number, const char **sysname)
128 {
129 regmatch_t m[2];
130 const char *devpath = udev_device_get_devpath(dev);
131
132 if (devpath != NULL &&
133 regexec(&card_regex, devpath, ARRAY_SIZE(m), m, 0) == 0) {
134 *sysname = udev_device_get_sysname(dev);
135 *internal = is_internal_device(dev);
136 *card_number = (unsigned)atoi(&devpath[m[1].rm_so]);
137 return 1;
138 }
139
140 return 0;
141 }
142
set_factory_default(unsigned card_number)143 static void set_factory_default(unsigned card_number)
144 {
145 static const char alsactl[] = "/usr/sbin/alsactl";
146 static const char asound_state[] = "/etc/asound.state";
147 char cmd_buf[128];
148 struct stat stat_buf;
149 int r;
150
151 if (stat(asound_state, &stat_buf) == 0) {
152 syslog(LOG_INFO, "%s: init card '%u' to factory default",
153 __FUNCTION__, card_number);
154 r = snprintf(cmd_buf, ARRAY_SIZE(cmd_buf),
155 "%s --file %s restore %u", alsactl, asound_state,
156 card_number);
157 cmd_buf[ARRAY_SIZE(cmd_buf) - 1] = '\0';
158 r = system(cmd_buf);
159 if (r != 0)
160 syslog(LOG_ERR,
161 "%s: failed to init card '%d' "
162 "to factory default. Failure: %d. Command: %s",
163 __FUNCTION__, card_number, r, cmd_buf);
164 }
165 }
166
udev_delay_for_alsa()167 static inline void udev_delay_for_alsa()
168 {
169 /* Provide a small delay so that the udev message can
170 * propogate throughout the whole system, and Alsa can set up
171 * the new device. Without a small delay, an error of the
172 * form:
173 *
174 * Fail opening control hw:?
175 *
176 * will be produced by cras_alsa_card_create().
177 */
178 usleep(125000); /* 0.125 second */
179 }
180
181 /* Reads the "descriptors" file of the usb device and returns the
182 * checksum of the contents. Returns 0 if the file can not be read */
calculate_desc_checksum(struct udev_device * dev)183 static uint32_t calculate_desc_checksum(struct udev_device *dev)
184 {
185 char path[MAX_DESC_NAME_LEN];
186 struct stat stat_buf;
187 int fd;
188 unsigned char *buf = NULL;
189 int buf_size = 0;
190 int read_size;
191 ssize_t n;
192 uint32_t result;
193
194 if (snprintf(path, sizeof(path), "%s/descriptors",
195 udev_device_get_syspath(dev)) >= sizeof(path)) {
196 syslog(LOG_ERR, "failed to build path");
197 return 0;
198 }
199
200 if (stat(path, &stat_buf) < 0) {
201 syslog(LOG_ERR, "failed to stat file %s: %s", path,
202 strerror(errno));
203 return 0;
204 }
205
206 fd = open(path, O_RDONLY);
207 if (fd < 0) {
208 syslog(LOG_ERR, "failed to open file %s: %s", path,
209 strerror(errno));
210 return 0;
211 }
212
213 read_size = 0;
214 while (read_size < stat_buf.st_size) {
215 if (read_size == buf_size) {
216 if (buf_size == 0)
217 buf_size = 256;
218 else
219 buf_size *= 2;
220 uint8_t *new_buf = realloc(buf, buf_size);
221 if (new_buf == NULL) {
222 syslog(LOG_ERR, "no memory to read file %s",
223 path);
224 goto bail;
225 }
226 buf = new_buf;
227 }
228 n = read(fd, buf + read_size, buf_size - read_size);
229 if (n == 0)
230 break;
231 if (n < 0) {
232 syslog(LOG_ERR, "failed to read file %s", path);
233 goto bail;
234 }
235 read_size += n;
236 }
237
238 close(fd);
239 result = crc32_checksum(buf, read_size);
240 free(buf);
241 return result;
242 bail:
243 close(fd);
244 free(buf);
245 return 0;
246 }
247
fill_usb_card_info(struct cras_alsa_card_info * card_info,struct udev_device * dev)248 static void fill_usb_card_info(struct cras_alsa_card_info *card_info,
249 struct udev_device *dev)
250 {
251 const char *sysattr;
252 struct udev_device *parent_dev =
253 udev_device_get_parent_with_subsystem_devtype(dev, "usb",
254 "usb_device");
255 if (!parent_dev)
256 return;
257
258 sysattr = udev_device_get_sysattr_value(parent_dev, "idVendor");
259 if (sysattr)
260 card_info->usb_vendor_id = strtol(sysattr, NULL, 16);
261 sysattr = udev_device_get_sysattr_value(parent_dev, "idProduct");
262 if (sysattr)
263 card_info->usb_product_id = strtol(sysattr, NULL, 16);
264 sysattr = udev_device_get_sysattr_value(parent_dev, "serial");
265 if (sysattr) {
266 strncpy(card_info->usb_serial_number, sysattr,
267 USB_SERIAL_NUMBER_BUFFER_SIZE - 1);
268 card_info->usb_serial_number[USB_SERIAL_NUMBER_BUFFER_SIZE - 1] =
269 '\0';
270 }
271
272 card_info->usb_desc_checksum = calculate_desc_checksum(parent_dev);
273
274 syslog(LOG_INFO,
275 "USB card: vendor:%04x, product:%04x, serial num:%s, "
276 "checksum:%08x",
277 card_info->usb_vendor_id, card_info->usb_product_id,
278 card_info->usb_serial_number, card_info->usb_desc_checksum);
279 }
280
device_add_alsa(struct udev_device * dev,const char * sysname,unsigned card,unsigned internal)281 static void device_add_alsa(struct udev_device *dev, const char *sysname,
282 unsigned card, unsigned internal)
283 {
284 struct cras_alsa_card_info card_info;
285 memset(&card_info, 0, sizeof(card_info));
286
287 udev_delay_for_alsa();
288 card_info.card_index = card;
289 if (internal) {
290 card_info.card_type = ALSA_CARD_TYPE_INTERNAL;
291 } else {
292 card_info.card_type = ALSA_CARD_TYPE_USB;
293 fill_usb_card_info(&card_info, dev);
294 }
295
296 cras_system_add_alsa_card(&card_info);
297 }
298
device_remove_alsa(const char * sysname,unsigned card)299 void device_remove_alsa(const char *sysname, unsigned card)
300 {
301 udev_delay_for_alsa();
302 cras_system_remove_alsa_card(card);
303 }
304
udev_sound_initialized(struct udev_device * dev)305 static int udev_sound_initialized(struct udev_device *dev)
306 {
307 /* udev will set SOUND_INITALIZED=1 for the main card node when the
308 * system has already been initialized, i.e. when cras is restarted
309 * on an already running system.
310 */
311 const char *s;
312
313 s = udev_device_get_property_value(dev, "SOUND_INITIALIZED");
314 if (s)
315 return 1;
316
317 return 0;
318 }
319
change_udev_device_if_alsa_device(struct udev_device * dev)320 static void change_udev_device_if_alsa_device(struct udev_device *dev)
321 {
322 /* If the device, 'dev' is an alsa device, add it to the set of
323 * devices available for I/O. Mark it as the active device.
324 */
325 unsigned internal;
326 unsigned card_number;
327 const char *sysname;
328
329 if (is_card_device(dev, &internal, &card_number, &sysname) &&
330 udev_sound_initialized(dev) &&
331 !cras_system_alsa_card_exists(card_number)) {
332 if (internal)
333 set_factory_default(card_number);
334 device_add_alsa(dev, sysname, card_number, internal);
335 }
336 }
337
remove_device_if_card(struct udev_device * dev)338 static void remove_device_if_card(struct udev_device *dev)
339 {
340 unsigned internal;
341 unsigned card_number;
342 const char *sysname;
343
344 if (is_card_device(dev, &internal, &card_number, &sysname))
345 device_remove_alsa(sysname, card_number);
346 }
347
enumerate_devices(struct udev_callback_data * data)348 static void enumerate_devices(struct udev_callback_data *data)
349 {
350 struct udev_enumerate *enumerate = udev_enumerate_new(data->udev);
351 struct udev_list_entry *dl;
352 struct udev_list_entry *dev_list_entry;
353
354 udev_enumerate_add_match_subsystem(enumerate, subsystem);
355 udev_enumerate_scan_devices(enumerate);
356 dl = udev_enumerate_get_list_entry(enumerate);
357
358 udev_list_entry_foreach(dev_list_entry, dl)
359 {
360 const char *path = udev_list_entry_get_name(dev_list_entry);
361 struct udev_device *dev =
362 udev_device_new_from_syspath(data->udev, path);
363
364 change_udev_device_if_alsa_device(dev);
365 udev_device_unref(dev);
366 }
367 udev_enumerate_unref(enumerate);
368 }
369
udev_sound_subsystem_callback(void * arg,int revents)370 static void udev_sound_subsystem_callback(void *arg, int revents)
371 {
372 struct udev_callback_data *data = (struct udev_callback_data *)arg;
373 struct udev_device *dev;
374
375 dev = udev_monitor_receive_device(data->mon);
376 if (dev) {
377 const char *action = udev_device_get_action(dev);
378
379 if (is_action_change(action))
380 change_udev_device_if_alsa_device(dev);
381 else if (is_action_remove(action))
382 remove_device_if_card(dev);
383 udev_device_unref(dev);
384 } else
385 syslog(LOG_WARNING,
386 "%s (internal error): "
387 "No device obtained",
388 __FUNCTION__);
389 }
390
compile_regex(regex_t * regex,const char * str)391 static void compile_regex(regex_t *regex, const char *str)
392 {
393 int r = regcomp(regex, str, REG_EXTENDED);
394 assert(r == 0);
395 }
396
397 static struct udev_callback_data udev_data;
cras_udev_start_sound_subsystem_monitor()398 void cras_udev_start_sound_subsystem_monitor()
399 {
400 int r;
401
402 udev_data.udev = udev_new();
403 assert(udev_data.udev != NULL);
404 udev_data.mon = udev_monitor_new_from_netlink(udev_data.udev, "udev");
405
406 udev_monitor_filter_add_match_subsystem_devtype(udev_data.mon,
407 subsystem, NULL);
408 udev_monitor_enable_receiving(udev_data.mon);
409 udev_data.fd = udev_monitor_get_fd(udev_data.mon);
410
411 r = cras_system_add_select_fd(udev_data.fd,
412 udev_sound_subsystem_callback, &udev_data,
413 POLLIN);
414 assert(r == 0);
415 compile_regex(&pcm_regex, pcm_regex_string);
416 compile_regex(&card_regex, card_regex_string);
417
418 enumerate_devices(&udev_data);
419 }
420
cras_udev_stop_sound_subsystem_monitor()421 void cras_udev_stop_sound_subsystem_monitor()
422 {
423 udev_unref(udev_data.udev);
424 regfree(&pcm_regex);
425 regfree(&card_regex);
426 }
427