1 /* Copyright (c) 2015 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 <errno.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <syslog.h> 10 11 #include "cras_main_message.h" 12 #include "cras_system_state.h" 13 #include "cras_util.h" 14 15 16 /* Callback to handle specific type of main thread message. */ 17 struct cras_main_msg_callback { 18 enum CRAS_MAIN_MESSAGE_TYPE type; 19 cras_message_callback callback; 20 void *callback_data; 21 struct cras_main_msg_callback *prev, *next; 22 }; 23 24 static int main_msg_fds[2]; 25 static struct cras_main_msg_callback *main_msg_callbacks; 26 27 int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type, 28 cras_message_callback callback, 29 void *callback_data) 30 { 31 struct cras_main_msg_callback *msg_cb; 32 33 DL_FOREACH(main_msg_callbacks, msg_cb) { 34 if (msg_cb->type == type) { 35 syslog(LOG_ERR, "Main message type %u already exists", 36 type); 37 return -EEXIST; 38 } 39 } 40 41 msg_cb = (struct cras_main_msg_callback *)calloc(1, sizeof(*msg_cb)); 42 msg_cb->type = type; 43 msg_cb->callback = callback; 44 msg_cb->callback_data = callback_data; 45 46 DL_APPEND(main_msg_callbacks, msg_cb); 47 return 0; 48 } 49 50 int cras_main_message_send(struct cras_main_message *msg) 51 { 52 int err; 53 54 err = write(main_msg_fds[1], msg, msg->length); 55 if (err < 0) { 56 syslog(LOG_ERR, "Failed to send main message, type %u", 57 msg->type); 58 return err; 59 } 60 return 0; 61 } 62 63 static int read_main_message(int msg_fd, uint8_t *buf, size_t max_len) { 64 int to_read, nread, rc; 65 struct cras_main_message *msg = (struct cras_main_message *)buf; 66 67 nread = read(msg_fd, buf, sizeof(msg->length)); 68 if (nread < 0) 69 return nread; 70 if (msg->length > max_len) 71 return -ENOMEM; 72 73 to_read = msg->length - nread; 74 rc = read(msg_fd, &buf[0] + nread, to_read); 75 if (rc < 0) 76 return rc; 77 return 0; 78 } 79 80 static void handle_main_messages(void *arg) 81 { 82 uint8_t buf[256]; 83 int rc; 84 struct cras_main_msg_callback *main_msg_cb; 85 struct cras_main_message *msg = (struct cras_main_message *)buf; 86 87 rc = read_main_message(main_msg_fds[0], buf, sizeof(buf)); 88 if (rc < 0) { 89 syslog(LOG_ERR, "Failed to read main message"); 90 return; 91 } 92 93 DL_FOREACH(main_msg_callbacks, main_msg_cb) { 94 if (main_msg_cb->type == msg->type) { 95 main_msg_cb->callback(msg, main_msg_cb->callback_data); 96 break; 97 } 98 } 99 } 100 101 void cras_main_message_init() { 102 int rc; 103 104 rc = pipe(main_msg_fds); 105 if (rc < 0) { 106 syslog(LOG_ERR, "Fatal: main message init"); 107 exit(-ENOMEM); 108 } 109 110 /* When full it's preferred to get error instead of blocked. */ 111 cras_make_fd_nonblocking(main_msg_fds[0]); 112 cras_make_fd_nonblocking(main_msg_fds[1]); 113 114 cras_system_add_select_fd(main_msg_fds[0], 115 handle_main_messages, 116 NULL); 117 } 118