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 };
17
18 struct cras_device_monitor_message {
19 struct cras_main_message header;
20 enum CRAS_DEVICE_MONITOR_MSG_TYPE message_type;
21 struct cras_iodev *iodev;
22 };
23
init_device_msg(struct cras_device_monitor_message * msg,enum CRAS_DEVICE_MONITOR_MSG_TYPE type,struct cras_iodev * iodev)24 static void init_device_msg(
25 struct cras_device_monitor_message *msg,
26 enum CRAS_DEVICE_MONITOR_MSG_TYPE type,
27 struct cras_iodev *iodev)
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->iodev = iodev;
34 }
35
cras_device_monitor_reset_device(struct cras_iodev * iodev)36 int cras_device_monitor_reset_device(struct cras_iodev *iodev)
37 {
38 struct cras_device_monitor_message msg;
39 int err;
40
41 init_device_msg(&msg, RESET_DEVICE, iodev);
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(struct cras_iodev * iodev)51 int cras_device_monitor_set_device_mute_state(struct cras_iodev *iodev)
52 {
53 struct cras_device_monitor_message msg;
54 int err;
55
56 init_device_msg(&msg, SET_MUTE_STATE, iodev);
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
66
67 /* When device is in a bad state, e.g. severe underrun,
68 * it might break how audio thread works and cause busy wake up loop.
69 * Resetting the device can bring device back to normal state.
70 * Let main thread follow the disable/enable sequence in iodev_list
71 * to properly close/open the device while enabling/disabling fallback
72 * device.
73 */
handle_device_message(struct cras_main_message * msg,void * arg)74 static void handle_device_message(struct cras_main_message *msg, void *arg)
75 {
76 struct cras_device_monitor_message *device_msg =
77 (struct cras_device_monitor_message *)msg;
78 struct cras_iodev *iodev = device_msg->iodev;
79
80 switch (device_msg->message_type) {
81 case RESET_DEVICE:
82 syslog(LOG_ERR, "trying to recover device 0x%x by resetting it",
83 iodev->info.idx);
84 cras_iodev_list_disable_dev(iodev, true);
85 cras_iodev_list_enable_dev(iodev);
86 break;
87 case SET_MUTE_STATE:
88 cras_iodev_set_mute(iodev);
89 break;
90 default:
91 syslog(LOG_ERR, "Unknown device message type %u",
92 device_msg->message_type);
93 break;
94 }
95 }
96
cras_device_monitor_init()97 int cras_device_monitor_init()
98 {
99 cras_main_message_add_handler(CRAS_MAIN_MONITOR_DEVICE,
100 handle_device_message, NULL);
101 return 0;
102 }
103