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
cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,cras_message_callback callback,void * callback_data)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
cras_main_message_send(struct cras_main_message * msg)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
read_main_message(int msg_fd,uint8_t * buf,size_t max_len)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
handle_main_messages(void * arg)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
cras_main_message_init()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