• 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, 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