• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2016 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 
6 #include <stdbool.h>
7 #include <syslog.h>
8 
9 #include "cras_device_monitor.h"
10 #include "cras_iodev_list.h"
11 #include "cras_main_message.h"
12 
13 enum CRAS_DEVICE_MONITOR_MSG_TYPE {
14 	RESET_DEVICE,
15 	SET_MUTE_STATE,
16 	ERROR_CLOSE,
17 };
18 
19 struct cras_device_monitor_message {
20 	struct cras_main_message header;
21 	enum CRAS_DEVICE_MONITOR_MSG_TYPE message_type;
22 	unsigned int dev_idx;
23 };
24 
init_device_msg(struct cras_device_monitor_message * msg,enum CRAS_DEVICE_MONITOR_MSG_TYPE type,unsigned int dev_idx)25 static void init_device_msg(struct cras_device_monitor_message *msg,
26 			    enum CRAS_DEVICE_MONITOR_MSG_TYPE type,
27 			    unsigned int dev_idx)
28 {
29 	memset(msg, 0, sizeof(*msg));
30 	msg->header.type = CRAS_MAIN_MONITOR_DEVICE;
31 	msg->header.length = sizeof(*msg);
32 	msg->message_type = type;
33 	msg->dev_idx = dev_idx;
34 }
35 
cras_device_monitor_reset_device(unsigned int dev_idx)36 int cras_device_monitor_reset_device(unsigned int dev_idx)
37 {
38 	struct cras_device_monitor_message msg;
39 	int err;
40 
41 	init_device_msg(&msg, RESET_DEVICE, dev_idx);
42 	err = cras_main_message_send((struct cras_main_message *)&msg);
43 	if (err < 0) {
44 		syslog(LOG_ERR, "Failed to send device message %d",
45 		       RESET_DEVICE);
46 		return err;
47 	}
48 	return 0;
49 }
50 
cras_device_monitor_set_device_mute_state(unsigned int dev_idx)51 int cras_device_monitor_set_device_mute_state(unsigned int dev_idx)
52 {
53 	struct cras_device_monitor_message msg;
54 	int err;
55 
56 	init_device_msg(&msg, SET_MUTE_STATE, dev_idx);
57 	err = cras_main_message_send((struct cras_main_message *)&msg);
58 	if (err < 0) {
59 		syslog(LOG_ERR, "Failed to send device message %d",
60 		       SET_MUTE_STATE);
61 		return err;
62 	}
63 	return 0;
64 }
65 
cras_device_monitor_error_close(unsigned int dev_idx)66 int cras_device_monitor_error_close(unsigned int dev_idx)
67 {
68 	struct cras_device_monitor_message msg;
69 	int err;
70 
71 	init_device_msg(&msg, ERROR_CLOSE, dev_idx);
72 	err = cras_main_message_send((struct cras_main_message *)&msg);
73 	if (err < 0) {
74 		syslog(LOG_ERR, "Failed to send device message %d",
75 		       ERROR_CLOSE);
76 		return err;
77 	}
78 	return 0;
79 }
80 
81 /* When device is in a bad state, e.g. severe underrun,
82  * it might break how audio thread works and cause busy wake up loop.
83  * Resetting the device can bring device back to normal state.
84  * Let main thread follow the disable/enable sequence in iodev_list
85   * to properly close/open the device while enabling/disabling fallback
86  * device.
87  */
handle_device_message(struct cras_main_message * msg,void * arg)88 static void handle_device_message(struct cras_main_message *msg, void *arg)
89 {
90 	struct cras_device_monitor_message *device_msg =
91 		(struct cras_device_monitor_message *)msg;
92 
93 	switch (device_msg->message_type) {
94 	case RESET_DEVICE:
95 		syslog(LOG_ERR, "trying to recover device 0x%x by resetting it",
96 		       device_msg->dev_idx);
97 		cras_iodev_list_suspend_dev(device_msg->dev_idx);
98 		cras_iodev_list_resume_dev(device_msg->dev_idx);
99 		break;
100 	case SET_MUTE_STATE:
101 		cras_iodev_list_set_dev_mute(device_msg->dev_idx);
102 		break;
103 	case ERROR_CLOSE:
104 		syslog(LOG_ERR, "Close erroneous device in main thread");
105 		cras_iodev_list_suspend_dev(device_msg->dev_idx);
106 		break;
107 	default:
108 		syslog(LOG_ERR, "Unknown device message type %u",
109 		       device_msg->message_type);
110 		break;
111 	}
112 }
113 
cras_device_monitor_init()114 int cras_device_monitor_init()
115 {
116 	cras_main_message_add_handler(CRAS_MAIN_MONITOR_DEVICE,
117 				      handle_device_message, NULL);
118 	return 0;
119 }
120