• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 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 /* Callback to handle specific type of main thread message. */
16 struct cras_main_msg_callback {
17 	enum CRAS_MAIN_MESSAGE_TYPE type;
18 	cras_message_callback callback;
19 	void *callback_data;
20 	struct cras_main_msg_callback *prev, *next;
21 };
22 
23 static int main_msg_fds[2];
24 static struct cras_main_msg_callback *main_msg_callbacks;
25 
cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,cras_message_callback callback,void * callback_data)26 int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,
27 				  cras_message_callback callback,
28 				  void *callback_data)
29 {
30 	struct cras_main_msg_callback *msg_cb;
31 
32 	DL_FOREACH (main_msg_callbacks, msg_cb) {
33 		if (msg_cb->type == type) {
34 			syslog(LOG_ERR, "Main message type %u already exists",
35 			       type);
36 			return -EEXIST;
37 		}
38 	}
39 
40 	msg_cb = (struct cras_main_msg_callback *)calloc(1, sizeof(*msg_cb));
41 	msg_cb->type = type;
42 	msg_cb->callback = callback;
43 	msg_cb->callback_data = callback_data;
44 
45 	DL_APPEND(main_msg_callbacks, msg_cb);
46 	return 0;
47 }
48 
cras_main_message_send(struct cras_main_message * msg)49 int cras_main_message_send(struct cras_main_message *msg)
50 {
51 	int err;
52 
53 	err = write(main_msg_fds[1], msg, msg->length);
54 	if (err < 0) {
55 		syslog(LOG_ERR, "Failed to send main message, type %u",
56 		       msg->type);
57 		return err;
58 	}
59 	return 0;
60 }
61 
read_main_message(int msg_fd,uint8_t * buf,size_t max_len)62 static int read_main_message(int msg_fd, uint8_t *buf, size_t max_len)
63 {
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 {
103 	int rc;
104 
105 	rc = pipe(main_msg_fds);
106 	if (rc < 0) {
107 		syslog(LOG_ERR, "Fatal: main message init");
108 		exit(-ENOMEM);
109 	}
110 
111 	/* When full it's preferred to get error instead of blocked. */
112 	cras_make_fd_nonblocking(main_msg_fds[0]);
113 	cras_make_fd_nonblocking(main_msg_fds[1]);
114 
115 	cras_system_add_select_fd(main_msg_fds[0], handle_main_messages, NULL);
116 }
117