• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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