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