1 /* 2 * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com. 3 * Copyright 2007-2010, Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 11 static status_t 12 multi_audio_control_generic(cookie_type* cookie, uint32 op, void* arg, size_t len) 13 { 14 status_t status; 15 switch (op) { 16 case B_MULTI_GET_DESCRIPTION: 17 { 18 multi_description description; 19 multi_channel_info channels[16]; 20 multi_channel_info* originalChannels; 21 22 if (user_memcpy(&description, arg, sizeof(multi_description)) 23 != B_OK) 24 return B_BAD_ADDRESS; 25 26 originalChannels = description.channels; 27 description.channels = channels; 28 if (description.request_channel_count > 16) 29 description.request_channel_count = 16; 30 31 status = get_description(cookie, &description); 32 if (status != B_OK) 33 return status; 34 35 description.channels = originalChannels; 36 if (user_memcpy(arg, &description, sizeof(multi_description)) 37 != B_OK) 38 return B_BAD_ADDRESS; 39 return user_memcpy(originalChannels, channels, 40 sizeof(multi_channel_info) * description.request_channel_count); 41 } 42 43 case B_MULTI_GET_ENABLED_CHANNELS: 44 { 45 multi_channel_enable* data = (multi_channel_enable*)arg; 46 multi_channel_enable enable; 47 uint32 enable_bits; 48 uchar* orig_enable_bits; 49 50 if (user_memcpy(&enable, data, sizeof(enable)) != B_OK 51 || !IS_USER_ADDRESS(enable.enable_bits)) { 52 return B_BAD_ADDRESS; 53 } 54 55 orig_enable_bits = enable.enable_bits; 56 enable.enable_bits = (uchar*)&enable_bits; 57 status = get_enabled_channels(cookie, &enable); 58 if (status != B_OK) 59 return status; 60 61 enable.enable_bits = orig_enable_bits; 62 if (user_memcpy(enable.enable_bits, &enable_bits, 63 sizeof(enable_bits)) < B_OK 64 || user_memcpy(arg, &enable, sizeof(multi_channel_enable)) < B_OK) { 65 return B_BAD_ADDRESS; 66 } 67 68 return B_OK; 69 } 70 case B_MULTI_SET_ENABLED_CHANNELS: 71 return B_OK; 72 73 case B_MULTI_GET_GLOBAL_FORMAT: 74 { 75 multi_format_info info; 76 if (user_memcpy(&info, arg, sizeof(multi_format_info)) != B_OK) 77 return B_BAD_ADDRESS; 78 79 status = get_global_format(cookie, &info); 80 if (status != B_OK) 81 return B_OK; 82 return user_memcpy(arg, &info, sizeof(multi_format_info)); 83 } 84 case B_MULTI_SET_GLOBAL_FORMAT: 85 { 86 multi_format_info info; 87 if (user_memcpy(&info, arg, sizeof(multi_format_info)) != B_OK) 88 return B_BAD_ADDRESS; 89 90 status = set_global_format(cookie, &info); 91 if (status != B_OK) 92 return B_OK; 93 return user_memcpy(arg, &info, sizeof(multi_format_info)); 94 } 95 case B_MULTI_LIST_MIX_CHANNELS: 96 return list_mix_channels(cookie, (multi_mix_channel_info*)arg); 97 case B_MULTI_LIST_MIX_CONTROLS: 98 { 99 multi_mix_control_info info; 100 multi_mix_control* original_controls; 101 size_t allocSize; 102 multi_mix_control *controls; 103 104 if (user_memcpy(&info, arg, sizeof(multi_mix_control_info)) != B_OK) 105 return B_BAD_ADDRESS; 106 107 original_controls = info.controls; 108 allocSize = sizeof(multi_mix_control) * info.control_count; 109 controls = (multi_mix_control *)malloc(allocSize); 110 if (controls == NULL) 111 return B_NO_MEMORY; 112 113 if (!IS_USER_ADDRESS(info.controls) 114 || user_memcpy(controls, info.controls, allocSize) < B_OK) { 115 free(controls); 116 return B_BAD_ADDRESS; 117 } 118 info.controls = controls; 119 120 status = list_mix_controls(cookie, &info); 121 if (status != B_OK) { 122 free(controls); 123 return status; 124 } 125 126 info.controls = original_controls; 127 status = user_memcpy(info.controls, controls, allocSize); 128 if (status == B_OK) 129 status = user_memcpy(arg, &info, sizeof(multi_mix_control_info)); 130 if (status != B_OK) 131 status = B_BAD_ADDRESS; 132 free(controls); 133 return status; 134 } 135 case B_MULTI_LIST_MIX_CONNECTIONS: 136 return list_mix_connections(cookie, 137 (multi_mix_connection_info*)arg); 138 case B_MULTI_GET_MIX: 139 { 140 multi_mix_value_info info; 141 multi_mix_value* original_values; 142 size_t allocSize; 143 multi_mix_value *values; 144 145 if (user_memcpy(&info, arg, sizeof(multi_mix_value_info)) != B_OK) 146 return B_BAD_ADDRESS; 147 148 original_values = info.values; 149 allocSize = sizeof(multi_mix_value) * info.item_count; 150 values = (multi_mix_value *)malloc(allocSize); 151 if (values == NULL) 152 return B_NO_MEMORY; 153 154 if (!IS_USER_ADDRESS(info.values) 155 || user_memcpy(values, info.values, allocSize) < B_OK) { 156 free(values); 157 return B_BAD_ADDRESS; 158 } 159 info.values = values; 160 161 status = get_mix(cookie, &info); 162 if (status != B_OK) { 163 free(values); 164 return status; 165 } 166 167 info.values = original_values; 168 status = user_memcpy(info.values, values, allocSize); 169 if (status == B_OK) 170 status = user_memcpy(arg, &info, sizeof(multi_mix_value_info)); 171 if (status != B_OK) 172 status = B_BAD_ADDRESS; 173 free(values); 174 return status; 175 } 176 case B_MULTI_SET_MIX: 177 { 178 multi_mix_value_info info; 179 multi_mix_value* original_values; 180 size_t allocSize; 181 multi_mix_value *values; 182 183 if (user_memcpy(&info, arg, sizeof(multi_mix_value_info)) != B_OK) 184 return B_BAD_ADDRESS; 185 186 original_values = info.values; 187 allocSize = sizeof(multi_mix_value) * info.item_count; 188 values = (multi_mix_value *)malloc(allocSize); 189 if (values == NULL) 190 return B_NO_MEMORY; 191 192 if (!IS_USER_ADDRESS(info.values) 193 || user_memcpy(values, info.values, allocSize) < B_OK) { 194 free(values); 195 return B_BAD_ADDRESS; 196 } 197 info.values = values; 198 199 status = set_mix(cookie, &info); 200 if (status != B_OK) { 201 free(values); 202 return status; 203 } 204 205 info.values = original_values; 206 status = user_memcpy(info.values, values, allocSize); 207 if (status == B_OK) 208 status = user_memcpy(arg, &info, sizeof(multi_mix_value_info)); 209 if (status != B_OK) 210 status = B_BAD_ADDRESS; 211 free(values); 212 return status; 213 } 214 case B_MULTI_GET_BUFFERS: 215 { 216 multi_buffer_list list; 217 if (user_memcpy(&list, arg, sizeof(multi_buffer_list)) != B_OK) 218 return B_BAD_ADDRESS; 219 { 220 buffer_desc **original_playback_descs = list.playback_buffers; 221 buffer_desc **original_record_descs = list.record_buffers; 222 223 buffer_desc *playback_descs[list.request_playback_buffers]; 224 buffer_desc *record_descs[list.request_record_buffers]; 225 226 if (!IS_USER_ADDRESS(list.playback_buffers) 227 || user_memcpy(playback_descs, list.playback_buffers, 228 sizeof(buffer_desc*) * list.request_playback_buffers) 229 < B_OK 230 || !IS_USER_ADDRESS(list.record_buffers) 231 || user_memcpy(record_descs, list.record_buffers, 232 sizeof(buffer_desc*) * list.request_record_buffers) 233 < B_OK) { 234 return B_BAD_ADDRESS; 235 } 236 237 list.playback_buffers = playback_descs; 238 list.record_buffers = record_descs; 239 status = get_buffers(cookie, &list); 240 if (status != B_OK) 241 return status; 242 243 list.playback_buffers = original_playback_descs; 244 list.record_buffers = original_record_descs; 245 246 if (user_memcpy(arg, &list, sizeof(multi_buffer_list)) < B_OK 247 || user_memcpy(original_playback_descs, playback_descs, 248 sizeof(buffer_desc*) * list.request_playback_buffers) 249 < B_OK 250 || user_memcpy(original_record_descs, record_descs, 251 sizeof(buffer_desc*) * list.request_record_buffers) 252 < B_OK) { 253 status = B_BAD_ADDRESS; 254 } 255 } 256 257 return status; 258 } 259 case B_MULTI_BUFFER_EXCHANGE: 260 return buffer_exchange(cookie, (multi_buffer_info*)arg); 261 case B_MULTI_BUFFER_FORCE_STOP: 262 return buffer_force_stop(cookie); 263 264 case B_MULTI_GET_EVENT_INFO: 265 case B_MULTI_SET_EVENT_INFO: 266 case B_MULTI_GET_EVENT: 267 case B_MULTI_GET_CHANNEL_FORMATS: 268 case B_MULTI_SET_CHANNEL_FORMATS: 269 case B_MULTI_SET_BUFFERS: 270 case B_MULTI_SET_START_TIME: 271 return B_ERROR; 272 } 273 274 return B_BAD_VALUE; 275 } 276 277