1 /* 2 * QEMU Character Hub Device 3 * 4 * Author: Roman Penyaev <r.peniaev@gmail.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "qapi/error.h" 27 #include "qemu/option.h" 28 #include "chardev/char.h" 29 #include "chardev-internal.h" 30 31 /* 32 * Character hub device aggregates input from multiple backend devices 33 * and forwards it to a single frontend device. Additionally, hub 34 * device takes the output from the frontend device and sends it back 35 * to all the connected backend devices. 36 */ 37 38 /* 39 * Write to all backends. Different backend devices accept data with 40 * various rate, so it is quite possible that one device returns less, 41 * then others. In this case we return minimum to the caller, 42 * expecting caller will repeat operation soon. When repeat happens 43 * send to the devices which consume data faster must be avoided 44 * for obvious reasons not to send data, which was already sent. 45 * Called with chr_write_lock held. 46 */ 47 static int hub_chr_write(Chardev *chr, const uint8_t *buf, int len) 48 { 49 HubChardev *d = HUB_CHARDEV(chr); 50 int r, i, ret = len; 51 unsigned int written; 52 53 /* Invalidate index on every write */ 54 d->be_eagain_ind = -1; 55 56 for (i = 0; i < d->be_cnt; i++) { 57 if (!d->backends[i].be.chr->be_open) { 58 /* Skip closed backend */ 59 continue; 60 } 61 written = d->be_written[i] - d->be_min_written; 62 if (written) { 63 /* Written in the previous call so take into account */ 64 ret = MIN(written, ret); 65 continue; 66 } 67 r = qemu_chr_fe_write(&d->backends[i].be, buf, len); 68 if (r < 0) { 69 if (errno == EAGAIN) { 70 /* Set index and expect to be called soon on watch wake up */ 71 d->be_eagain_ind = i; 72 } 73 return r; 74 } 75 d->be_written[i] += r; 76 ret = MIN(r, ret); 77 } 78 d->be_min_written += ret; 79 80 81 return ret; 82 } 83 84 static int hub_chr_can_read(void *opaque) 85 { 86 HubCharBackend *backend = opaque; 87 CharBackend *fe = backend->hub->parent.be; 88 89 if (fe && fe->chr_can_read) { 90 return fe->chr_can_read(fe->opaque); 91 } 92 93 return 0; 94 } 95 96 static void hub_chr_read(void *opaque, const uint8_t *buf, int size) 97 { 98 HubCharBackend *backend = opaque; 99 CharBackend *fe = backend->hub->parent.be; 100 101 if (fe && fe->chr_read) { 102 fe->chr_read(fe->opaque, buf, size); 103 } 104 } 105 106 static void hub_chr_event(void *opaque, QEMUChrEvent event) 107 { 108 HubCharBackend *backend = opaque; 109 HubChardev *d = backend->hub; 110 CharBackend *fe = d->parent.be; 111 112 if (event == CHR_EVENT_OPENED) { 113 /* 114 * Catch up with what was already written while this backend 115 * was closed 116 */ 117 d->be_written[backend->be_ind] = d->be_min_written; 118 119 if (d->be_event_opened_cnt++) { 120 /* Ignore subsequent open events from other backends */ 121 return; 122 } 123 } else if (event == CHR_EVENT_CLOSED) { 124 if (!d->be_event_opened_cnt) { 125 /* Don't go below zero. Probably assert is better */ 126 return; 127 } 128 if (--d->be_event_opened_cnt) { 129 /* Serve only the last one close event */ 130 return; 131 } 132 } 133 134 if (fe && fe->chr_event) { 135 fe->chr_event(fe->opaque, event); 136 } 137 } 138 139 static GSource *hub_chr_add_watch(Chardev *s, GIOCondition cond) 140 { 141 HubChardev *d = HUB_CHARDEV(s); 142 Chardev *chr; 143 ChardevClass *cc; 144 145 if (d->be_eagain_ind == -1) { 146 return NULL; 147 } 148 149 assert(d->be_eagain_ind < d->be_cnt); 150 chr = qemu_chr_fe_get_driver(&d->backends[d->be_eagain_ind].be); 151 cc = CHARDEV_GET_CLASS(chr); 152 if (!cc->chr_add_watch) { 153 return NULL; 154 } 155 156 return cc->chr_add_watch(chr, cond); 157 } 158 159 static bool hub_chr_attach_chardev(HubChardev *d, Chardev *chr, 160 Error **errp) 161 { 162 bool ret; 163 164 if (d->be_cnt >= MAX_HUB) { 165 error_setg(errp, "hub: too many uses of chardevs '%s'" 166 " (maximum is " stringify(MAX_HUB) ")", 167 d->parent.label); 168 return false; 169 } 170 ret = qemu_chr_fe_init(&d->backends[d->be_cnt].be, chr, errp); 171 if (ret) { 172 d->backends[d->be_cnt].hub = d; 173 d->backends[d->be_cnt].be_ind = d->be_cnt; 174 d->be_cnt += 1; 175 } 176 177 return ret; 178 } 179 180 static void char_hub_finalize(Object *obj) 181 { 182 HubChardev *d = HUB_CHARDEV(obj); 183 int i; 184 185 for (i = 0; i < d->be_cnt; i++) { 186 qemu_chr_fe_deinit(&d->backends[i].be, false); 187 } 188 } 189 190 static void hub_chr_update_read_handlers(Chardev *chr) 191 { 192 HubChardev *d = HUB_CHARDEV(chr); 193 int i; 194 195 for (i = 0; i < d->be_cnt; i++) { 196 qemu_chr_fe_set_handlers_full(&d->backends[i].be, 197 hub_chr_can_read, 198 hub_chr_read, 199 hub_chr_event, 200 NULL, 201 &d->backends[i], 202 chr->gcontext, true, false); 203 } 204 } 205 206 static void qemu_chr_open_hub(Chardev *chr, 207 ChardevBackend *backend, 208 bool *be_opened, 209 Error **errp) 210 { 211 ChardevHub *hub = backend->u.hub.data; 212 HubChardev *d = HUB_CHARDEV(chr); 213 strList *list = hub->chardevs; 214 215 d->be_eagain_ind = -1; 216 217 if (list == NULL) { 218 error_setg(errp, "hub: 'chardevs' list is not defined"); 219 return; 220 } 221 222 while (list) { 223 Chardev *s; 224 225 s = qemu_chr_find(list->value); 226 if (s == NULL) { 227 error_setg(errp, "hub: chardev can't be found by id '%s'", 228 list->value); 229 return; 230 } 231 if (CHARDEV_IS_HUB(s) || CHARDEV_IS_MUX(s)) { 232 error_setg(errp, "hub: multiplexers and hub devices can't be " 233 "stacked, check chardev '%s', chardev should not " 234 "be a hub device or have 'mux=on' enabled", 235 list->value); 236 return; 237 } 238 if (!hub_chr_attach_chardev(d, s, errp)) { 239 return; 240 } 241 list = list->next; 242 } 243 244 /* Closed until an explicit event from backend */ 245 *be_opened = false; 246 } 247 248 static void qemu_chr_parse_hub(QemuOpts *opts, ChardevBackend *backend, 249 Error **errp) 250 { 251 ChardevHub *hub; 252 strList **tail; 253 int i; 254 255 backend->type = CHARDEV_BACKEND_KIND_HUB; 256 hub = backend->u.hub.data = g_new0(ChardevHub, 1); 257 qemu_chr_parse_common(opts, qapi_ChardevHub_base(hub)); 258 259 tail = &hub->chardevs; 260 261 for (i = 0; i < MAX_HUB; i++) { 262 char optbuf[16]; 263 const char *dev; 264 265 snprintf(optbuf, sizeof(optbuf), "chardevs.%u", i); 266 dev = qemu_opt_get(opts, optbuf); 267 if (!dev) { 268 break; 269 } 270 271 QAPI_LIST_APPEND(tail, g_strdup(dev)); 272 } 273 } 274 275 static void char_hub_class_init(ObjectClass *oc, void *data) 276 { 277 ChardevClass *cc = CHARDEV_CLASS(oc); 278 279 cc->parse = qemu_chr_parse_hub; 280 cc->open = qemu_chr_open_hub; 281 cc->chr_write = hub_chr_write; 282 cc->chr_add_watch = hub_chr_add_watch; 283 /* We handle events from backends only */ 284 cc->chr_be_event = NULL; 285 cc->chr_update_read_handler = hub_chr_update_read_handlers; 286 } 287 288 static const TypeInfo char_hub_type_info = { 289 .name = TYPE_CHARDEV_HUB, 290 .parent = TYPE_CHARDEV, 291 .class_init = char_hub_class_init, 292 .instance_size = sizeof(HubChardev), 293 .instance_finalize = char_hub_finalize, 294 }; 295 296 static void register_types(void) 297 { 298 type_register_static(&char_hub_type_info); 299 } 300 301 type_init(register_types); 302