1 /////////////////////////////////////////////////////////////////////////
2 // $Id: plugin.cc 14214 2021-04-03 18:26:03Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002-2021 The Bochs Project
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 /////////////////////////////////////////////////////////////////////////
22 //
23 // This file defines the plugin and plugin-device registration functions and
24 // the device registration functions. It handles dynamic loading of modules,
25 // using the LTDL library for cross-platform support.
26 //
27 // This file is based on the plugin.c file from plex86, but with significant
28 // changes to make it work in Bochs.
29 // Plex86 is Copyright (C) 1999-2000 The plex86 developers team
30 //
31 /////////////////////////////////////////////////////////////////////////
32
33 #include "bochs.h"
34 #include "iodev/iodev.h"
35 #include "plugin.h"
36
37 #ifndef WIN32
38 #include <dirent.h> /* opendir, readdir */
39 #include <locale.h> /* setlocale */
40 #endif
41
42 #define LOG_THIS genlog->
43
44 #define PLUGIN_ENTRY_FMT_STRING "lib%s_plugin_entry"
45 #define GUI_PLUGIN_ENTRY_FMT_STRING "lib%s_gui_plugin_entry"
46 #define IMG_PLUGIN_ENTRY_FMT_STRING "lib%s_img_plugin_entry"
47 #define NET_PLUGIN_ENTRY_FMT_STRING "libeth_%s_plugin_entry"
48 #define SND_PLUGIN_ENTRY_FMT_STRING "libsound%s_plugin_entry"
49
50 #define PLUGIN_PATH ""
51
52 #ifndef WIN32
53 #define PLUGIN_FILENAME_FORMAT "libbx_%s.so"
54 #define GUI_PLUGIN_FILENAME_FORMAT "libbx_%s_gui.so"
55 #define IMG_PLUGIN_FILENAME_FORMAT "libbx_%s_img.so"
56 #define NET_PLUGIN_FILENAME_FORMAT "libbx_eth_%s.so"
57 #define SND_PLUGIN_FILENAME_FORMAT "libbx_sound%s.so"
58 #else
59 #define PLUGIN_FILENAME_FORMAT "bx_%s.dll"
60 #define GUI_PLUGIN_FILENAME_FORMAT "bx_%s_gui.dll"
61 #define IMG_PLUGIN_FILENAME_FORMAT "bx_%s_img.dll"
62 #define NET_PLUGIN_FILENAME_FORMAT "bx_eth_%s.dll"
63 #define SND_PLUGIN_FILENAME_FORMAT "bx_sound%s.dll"
64 #endif
65
66 logfunctions *pluginlog;
67
68 extern "C" {
69
70 void (*pluginRegisterIRQ)(unsigned irq, const char* name) = 0;
71 void (*pluginUnregisterIRQ)(unsigned irq, const char* name) = 0;
72
73 void (*pluginSetHRQ)(unsigned val) = 0;
74 void (*pluginSetHRQHackCallback)(void (*callback)(void)) = 0;
75
76 int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
77 unsigned base, const char *name, Bit8u mask) = 0;
78 int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
79 unsigned base, const char *name, Bit8u mask) = 0;
80 int (*pluginUnregisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
81 unsigned base, Bit8u mask) = 0;
82 int (*pluginUnregisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
83 unsigned base, Bit8u mask) = 0;
84 int (*pluginRegisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback,
85 unsigned base, unsigned end, const char *name, Bit8u mask) = 0;
86 int (*pluginRegisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback,
87 unsigned base, unsigned end, const char *name, Bit8u mask) = 0;
88 int (*pluginUnregisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback,
89 unsigned begin, unsigned end, Bit8u mask) = 0;
90 int (*pluginUnregisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback,
91 unsigned begin, unsigned end, Bit8u mask) = 0;
92 int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
93 const char *name, Bit8u mask) = 0;
94 int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
95 const char *name, Bit8u mask) = 0;
96
97 void (*pluginHRQHackCallback)(void);
98 unsigned pluginHRQ = 0;
99
100 plugin_t *plugins = NULL; /* Head of the linked list of plugins */
101 device_t *devices = NULL; /* Head of the linked list of registered devices */
102 device_t *core_devices = NULL; /* Head of the linked list of registered core devices */
103
104 plugin_t *current_plugin_context = NULL;
105
106 /************************************************************************/
107 /* Builtins declarations */
108 /************************************************************************/
109
110 static void
builtinRegisterIRQ(unsigned irq,const char * name)111 builtinRegisterIRQ(unsigned irq, const char* name)
112 {
113 bx_devices.register_irq(irq, name);
114 }
115
116 static void
builtinUnregisterIRQ(unsigned irq,const char * name)117 builtinUnregisterIRQ(unsigned irq, const char* name)
118 {
119 bx_devices.unregister_irq(irq, name);
120 }
121
122 static void
builtinSetHRQ(unsigned val)123 builtinSetHRQ(unsigned val)
124 {
125 pluginHRQ = val;
126 }
127
128 static void
builtinSetHRQHackCallback(void (* callback)(void))129 builtinSetHRQHackCallback(void (*callback)(void))
130 {
131 pluginHRQHackCallback = callback;
132 }
133
134 static int
builtinRegisterIOReadHandler(void * thisPtr,ioReadHandler_t callback,unsigned base,const char * name,Bit8u mask)135 builtinRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback,
136 unsigned base, const char *name, Bit8u mask)
137 {
138 int ret;
139 BX_ASSERT(mask<8);
140 ret = bx_devices.register_io_read_handler (thisPtr, callback, base, name, mask);
141 pluginlog->ldebug("plugin %s registered I/O read address at %04x", name, base);
142 return ret;
143 }
144
145 static int
builtinRegisterIOWriteHandler(void * thisPtr,ioWriteHandler_t callback,unsigned base,const char * name,Bit8u mask)146 builtinRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
147 unsigned base, const char *name, Bit8u mask)
148 {
149 int ret;
150 BX_ASSERT(mask<8);
151 ret = bx_devices.register_io_write_handler (thisPtr, callback, base, name, mask);
152 pluginlog->ldebug("plugin %s registered I/O write address at %04x", name, base);
153 return ret;
154 }
155
156 static int
builtinUnregisterIOReadHandler(void * thisPtr,ioReadHandler_t callback,unsigned base,Bit8u mask)157 builtinUnregisterIOReadHandler(void *thisPtr, ioReadHandler_t callback,
158 unsigned base, Bit8u mask)
159 {
160 int ret;
161 BX_ASSERT(mask<8);
162 ret = bx_devices.unregister_io_read_handler (thisPtr, callback, base, mask);
163 pluginlog->ldebug("plugin unregistered I/O read address at %04x", base);
164 return ret;
165 }
166
167 static int
builtinUnregisterIOWriteHandler(void * thisPtr,ioWriteHandler_t callback,unsigned base,Bit8u mask)168 builtinUnregisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
169 unsigned base, Bit8u mask)
170 {
171 int ret;
172 BX_ASSERT(mask<8);
173 ret = bx_devices.unregister_io_write_handler (thisPtr, callback, base, mask);
174 pluginlog->ldebug("plugin unregistered I/O write address at %04x", base);
175 return ret;
176 }
177
178 static int
builtinRegisterIOReadHandlerRange(void * thisPtr,ioReadHandler_t callback,unsigned base,unsigned end,const char * name,Bit8u mask)179 builtinRegisterIOReadHandlerRange(void *thisPtr, ioReadHandler_t callback,
180 unsigned base, unsigned end, const char *name, Bit8u mask)
181 {
182 int ret;
183 BX_ASSERT(mask<8);
184 ret = bx_devices.register_io_read_handler_range (thisPtr, callback, base, end, name, mask);
185 pluginlog->ldebug("plugin %s registered I/O read addresses %04x to %04x", name, base, end);
186 return ret;
187 }
188
189 static int
builtinRegisterIOWriteHandlerRange(void * thisPtr,ioWriteHandler_t callback,unsigned base,unsigned end,const char * name,Bit8u mask)190 builtinRegisterIOWriteHandlerRange(void *thisPtr, ioWriteHandler_t callback,
191 unsigned base, unsigned end, const char *name, Bit8u mask)
192 {
193 int ret;
194 BX_ASSERT(mask<8);
195 ret = bx_devices.register_io_write_handler_range (thisPtr, callback, base, end, name, mask);
196 pluginlog->ldebug("plugin %s registered I/O write addresses %04x to %04x", name, base, end);
197 return ret;
198 }
199
200 static int
builtinUnregisterIOReadHandlerRange(void * thisPtr,ioReadHandler_t callback,unsigned begin,unsigned end,Bit8u mask)201 builtinUnregisterIOReadHandlerRange(void *thisPtr, ioReadHandler_t callback,
202 unsigned begin, unsigned end, Bit8u mask)
203 {
204 int ret;
205 BX_ASSERT(mask<8);
206 ret = bx_devices.unregister_io_read_handler_range (thisPtr, callback, begin, end, mask);
207 pluginlog->ldebug("plugin unregistered I/O read addresses %04x to %04x", begin, end);
208 return ret;
209 }
210
211 static int
builtinUnregisterIOWriteHandlerRange(void * thisPtr,ioWriteHandler_t callback,unsigned begin,unsigned end,Bit8u mask)212 builtinUnregisterIOWriteHandlerRange(void *thisPtr, ioWriteHandler_t callback,
213 unsigned begin, unsigned end, Bit8u mask)
214 {
215 int ret;
216 BX_ASSERT(mask<8);
217 ret = bx_devices.unregister_io_write_handler_range (thisPtr, callback, begin, end, mask);
218 pluginlog->ldebug("plugin unregistered I/O write addresses %04x to %04x", begin, end);
219 return ret;
220 }
221
222 static int
builtinRegisterDefaultIOReadHandler(void * thisPtr,ioReadHandler_t callback,const char * name,Bit8u mask)223 builtinRegisterDefaultIOReadHandler(void *thisPtr, ioReadHandler_t callback,
224 const char *name, Bit8u mask)
225 {
226 BX_ASSERT(mask<8);
227 bx_devices.register_default_io_read_handler (thisPtr, callback, name, mask);
228 pluginlog->ldebug("plugin %s registered default I/O read ", name);
229 return 0;
230 }
231
232 static int
builtinRegisterDefaultIOWriteHandler(void * thisPtr,ioWriteHandler_t callback,const char * name,Bit8u mask)233 builtinRegisterDefaultIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
234 const char *name, Bit8u mask)
235 {
236 BX_ASSERT(mask<8);
237 bx_devices.register_default_io_write_handler (thisPtr, callback, name, mask);
238 pluginlog->ldebug("plugin %s registered default I/O write ", name);
239 return 0;
240 }
241
242 #if BX_PLUGINS
243 /************************************************************************/
244 /* Search for all available plugins */
245 /************************************************************************/
246
plugin_add_entry(char * pgn_name,Bit16u type,Bit8u flags)247 void plugin_add_entry(char *pgn_name, Bit16u type, Bit8u flags)
248 {
249 plugin_t *plugin, *temp;
250
251 if ((type & PLUGTYPE_GUI) > 0) {
252 if (!strncmp(pgn_name + strlen(pgn_name) - 4, "_gui", 4)) {
253 pgn_name[strlen(pgn_name) - 4] = 0;
254 }
255 } else if (type == PLUGTYPE_IMG) {
256 if (!strncmp(pgn_name + strlen(pgn_name) - 4, "_img", 4)) {
257 pgn_name[strlen(pgn_name) - 4] = 0;
258 }
259 } else if (type == PLUGTYPE_NET) {
260 if (!strncmp(pgn_name, "eth_", 4)) {
261 memmove(pgn_name, pgn_name + 4, strlen(pgn_name) - 3);
262 }
263 } else if (type == PLUGTYPE_SND) {
264 if (!strncmp(pgn_name, "sound", 5)) {
265 memmove(pgn_name, pgn_name + 5, strlen(pgn_name) - 4);
266 }
267 }
268 plugin = new plugin_t;
269 plugin->type = type;
270 plugin->flags = flags;
271 plugin->name = pgn_name;
272 plugin->loadtype = PLUGTYPE_NULL;
273 plugin->initialized = 0;
274 /* Insert plugin at the _end_ of the plugin linked list. */
275 plugin->next = NULL;
276 if (plugins == NULL) {
277 /* Empty list, this become the first entry. */
278 plugins = plugin;
279 } else {
280 /* Non-empty list. Add to end. */
281 temp = plugins;
282
283 while (temp->next)
284 temp = temp->next;
285
286 temp->next = plugin;
287 }
288 }
289
plugins_search(void)290 void plugins_search(void)
291 {
292 int nlen, flen1, flen2;
293 char *fmtptr, *ltdl_path_var, *pgn_name, *pgn_path, *ptr;
294 char fmtstr[32];
295 #ifndef WIN32
296 const char *path_sep = ":";
297 DIR *dir;
298 struct dirent *dent;
299 lt_dlhandle handle;
300 #else
301 const char *path_sep = ";";
302 WIN32_FIND_DATA finddata;
303 HANDLE hFind;
304 char filter[MAX_PATH];
305 char path[MAX_PATH];
306 HINSTANCE handle;
307 #endif
308 char tmpname[BX_PATHNAME_LEN];
309 plugin_entry_t plugin_entry;
310 Bit16u type;
311 Bit8u flags;
312
313 #ifndef WIN32
314 setlocale(LC_ALL, "en_US");
315 #endif
316 ltdl_path_var = getenv("LTDL_LIBRARY_PATH");
317 sprintf(fmtstr, PLUGIN_FILENAME_FORMAT, "*");
318 fmtptr = strchr(fmtstr, '*');
319 flen1 = fmtptr - fmtstr;
320 flen2 = strlen(fmtstr) - flen1 - 1;
321 if (ltdl_path_var != NULL) {
322 pgn_path = new char[strlen(ltdl_path_var) + 1];
323 strcpy(pgn_path, ltdl_path_var);
324 } else {
325 pgn_path = new char[2];
326 strcpy(pgn_path, ".");
327 }
328 ptr = strtok(pgn_path, path_sep);
329 while (ptr != NULL) {
330 #ifndef WIN32
331 dir = opendir(ptr);
332 if (dir != NULL) {
333 while ((dent=readdir(dir)) != NULL) {
334 nlen = strlen(dent->d_name);
335 if ((!strncmp(dent->d_name, fmtstr, flen1)) &&
336 (!strcmp(dent->d_name + nlen - flen2, fmtptr + 1))) {
337 pgn_name = new char[nlen - flen1 - flen2 + 1];
338 strncpy(pgn_name, dent->d_name + flen1, nlen - flen1 - flen2);
339 pgn_name[nlen - flen1 - flen2] = 0;
340 handle = lt_dlopen(dent->d_name);
341 if (handle) {
342 sprintf(tmpname, PLUGIN_ENTRY_FMT_STRING, pgn_name);
343 plugin_entry = (plugin_entry_t) lt_dlsym(handle, tmpname);
344 if (plugin_entry != NULL) {
345 type = (Bit16u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_PROBE);
346 flags = (Bit8u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_FLAGS);
347 plugin_add_entry(pgn_name, type, flags);
348 }
349 lt_dlclose(handle);
350 } else {
351 delete [] pgn_name;
352 }
353 }
354 }
355 closedir(dir);
356 }
357 #else
358 sprintf(filter, "%s\\*.dll", ptr);
359 hFind = FindFirstFile(filter, &finddata);
360 if (hFind != INVALID_HANDLE_VALUE) {
361 do {
362 nlen = lstrlen(finddata.cFileName);
363 if ((!strncmp(finddata.cFileName, fmtstr, flen1)) &&
364 (!strcmp(finddata.cFileName + nlen - flen2, fmtptr + 1))) {
365 pgn_name = new char[nlen - flen1 - flen2 + 1];
366 strncpy(pgn_name, finddata.cFileName + flen1, nlen - flen1 - flen2);
367 pgn_name[nlen - flen1 - flen2] = 0;
368 sprintf(path, "%s\\%s", ptr, finddata.cFileName);
369 handle = LoadLibrary(path);
370 if (handle) {
371 sprintf(tmpname, PLUGIN_ENTRY_FMT_STRING, pgn_name);
372 plugin_entry = (plugin_entry_t) GetProcAddress(handle, tmpname);
373 if (plugin_entry != NULL) {
374 type = (Bit16u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_PROBE);
375 flags = (Bit8u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_FLAGS);
376 plugin_add_entry(pgn_name, type, flags);
377 }
378 FreeLibrary(handle);
379 }
380 }
381 } while (FindNextFile(hFind, &finddata));
382 FindClose(hFind);
383 }
384 #endif
385 ptr = strtok(NULL, ":");
386 }
387 delete [] pgn_path;
388 }
389
bx_get_plugins_count(Bit16u type)390 Bit8u bx_get_plugins_count(Bit16u type)
391 {
392 plugin_t *temp;
393 Bit8u count = 0;
394
395 if (plugins != NULL) {
396 temp = plugins;
397
398 while (temp != NULL) {
399 if ((type & temp->type) != 0)
400 count++;
401 temp = temp->next;
402 }
403 }
404 return count;
405 }
406
bx_get_plugin_name(Bit16u type,Bit8u index)407 const char* bx_get_plugin_name(Bit16u type, Bit8u index)
408 {
409 plugin_t *temp;
410 int count = 0;
411
412 if (plugins != NULL) {
413 temp = plugins;
414
415 while (temp != NULL) {
416 if ((type & temp->type) != 0) {
417 if (count == index)
418 return temp->name;
419 count++;
420 }
421 temp = temp->next;
422 }
423 }
424 return NULL;
425 }
426
bx_get_plugin_flags(Bit16u type,Bit8u index)427 Bit8u bx_get_plugin_flags(Bit16u type, Bit8u index)
428 {
429 plugin_t *temp;
430 int count = 0;
431
432 if (plugins != NULL) {
433 temp = plugins;
434
435 while (temp != NULL) {
436 if ((type & temp->type) != 0) {
437 if (count == index)
438 return temp->flags;
439 count++;
440 }
441 temp = temp->next;
442 }
443 }
444 return 0;
445 }
446
447 /************************************************************************/
448 /* Plugin initialization / deinitialization */
449 /************************************************************************/
450
plugin_init_one(plugin_t * plugin)451 bool plugin_init_one(plugin_t *plugin)
452 {
453 /* initialize the plugin */
454 if (plugin->plugin_entry(plugin, plugin->loadtype, PLUGIN_INIT))
455 {
456 pluginlog->info("Plugin initialization failed for %s", plugin->name);
457 plugin_abort(plugin);
458 return 0;
459 }
460 plugin->initialized = 1;
461 return 1;
462 }
463
464
plugin_unload(plugin_t * plugin)465 bool plugin_unload(plugin_t *plugin)
466 {
467 if (plugin->loadtype != PLUGTYPE_NULL) {
468 if (plugin->initialized)
469 plugin->plugin_entry(plugin, plugin->type, PLUGIN_FINI);
470 #if defined(WIN32)
471 FreeLibrary(plugin->handle);
472 #else
473 lt_dlclose(plugin->handle);
474 #endif
475 plugin->loadtype = PLUGTYPE_NULL;
476 return 1;
477 } else {
478 return 0;
479 }
480 }
481
plugin_load(const char * name,Bit16u type)482 bool plugin_load(const char *name, Bit16u type)
483 {
484 plugin_t *plugin = NULL, *temp;
485 #if defined(WIN32)
486 char dll_path_list[MAX_PATH];
487 #endif
488
489 if (plugins != NULL) {
490 temp = plugins;
491
492 while (temp != NULL) {
493 if (!strcmp(name, temp->name) && ((type & temp->type) != 0)) {
494 if (temp->loadtype != PLUGTYPE_NULL) {
495 BX_PANIC(("plugin '%s' already loaded", name));
496 return 0;
497 } else {
498 plugin = temp;
499 break;
500 }
501 }
502 temp = temp->next;
503 }
504 }
505 if (plugin == NULL) {
506 BX_PANIC(("plugin '%s' not found", name));
507 return 0;
508 }
509
510 char plugin_filename[BX_PATHNAME_LEN], tmpname[BX_PATHNAME_LEN];
511 if (type == PLUGTYPE_GUI) {
512 sprintf(tmpname, GUI_PLUGIN_FILENAME_FORMAT, name);
513 } else if (type == PLUGTYPE_IMG) {
514 sprintf(tmpname, IMG_PLUGIN_FILENAME_FORMAT, name);
515 } else if (type == PLUGTYPE_NET) {
516 sprintf(tmpname, NET_PLUGIN_FILENAME_FORMAT, name);
517 } else if (type == PLUGTYPE_SND) {
518 sprintf(tmpname, SND_PLUGIN_FILENAME_FORMAT, name);
519 } else {
520 sprintf(tmpname, PLUGIN_FILENAME_FORMAT, name);
521 }
522 sprintf(plugin_filename, "%s%s", PLUGIN_PATH, tmpname);
523
524 // Set context so that any devices that the plugin registers will
525 // be able to see which plugin created them. The registration will
526 // be called from either dlopen (global constructors) or plugin_entry.
527 BX_ASSERT(current_plugin_context == NULL);
528 current_plugin_context = plugin;
529 #if defined(WIN32)
530 char *ptr;
531 plugin->handle = LoadLibrary(plugin_filename);
532 if (!plugin->handle) {
533 if (GetEnvironmentVariable("LTDL_LIBRARY_PATH", dll_path_list, MAX_PATH)) {
534 ptr = strtok(dll_path_list, ";");
535 while ((ptr) && !plugin->handle) {
536 sprintf(plugin_filename, "%s\\%s", ptr, tmpname);
537 plugin->handle = LoadLibrary(plugin_filename);
538 ptr = strtok(NULL, ";");
539 }
540 }
541 }
542 BX_INFO(("DLL handle is %p", plugin->handle));
543 if (!plugin->handle) {
544 current_plugin_context = NULL;
545 BX_PANIC(("LoadLibrary failed for module '%s' (%s): error=%d", name,
546 plugin_filename, GetLastError()));
547 return 0;
548 }
549 #else
550 plugin->handle = lt_dlopen(plugin_filename);
551 BX_INFO(("lt_dlhandle is %p", plugin->handle));
552 if (!plugin->handle) {
553 current_plugin_context = NULL;
554 BX_PANIC(("dlopen failed for module '%s' (%s): %s", name, plugin_filename,
555 lt_dlerror()));
556 return 0;
557 }
558 #endif
559 plugin->loadtype = type;
560
561 if (type == PLUGTYPE_GUI) {
562 sprintf(tmpname, GUI_PLUGIN_ENTRY_FMT_STRING, name);
563 } else if (type == PLUGTYPE_IMG) {
564 sprintf(tmpname, IMG_PLUGIN_ENTRY_FMT_STRING, name);
565 } else if (type == PLUGTYPE_NET) {
566 sprintf(tmpname, NET_PLUGIN_ENTRY_FMT_STRING, name);
567 } else if (type == PLUGTYPE_SND) {
568 sprintf(tmpname, SND_PLUGIN_ENTRY_FMT_STRING, name);
569 } else {
570 sprintf(tmpname, PLUGIN_ENTRY_FMT_STRING, name);
571 }
572 #if defined(WIN32)
573 plugin->plugin_entry = (plugin_entry_t) GetProcAddress(plugin->handle, tmpname);
574 if (plugin->plugin_entry == NULL) {
575 pluginlog->panic("could not find plugin_entry for module '%s' (%s): error=%d",
576 name, plugin_filename, GetLastError());
577 plugin_abort(plugin);
578 return 0;
579 }
580 #else
581 plugin->plugin_entry = (plugin_entry_t) lt_dlsym(plugin->handle, tmpname);
582 if (plugin->plugin_entry == NULL) {
583 pluginlog->panic("could not find plugin_entry for module '%s' (%s): %s",
584 name, plugin_filename, lt_dlerror());
585 plugin_abort(plugin);
586 return 0;
587 }
588 #endif
589 pluginlog->info("loaded plugin %s",plugin_filename);
590
591 if (!plugin_init_one(plugin)) {
592 return 0;
593 }
594
595 // check that context didn't change. This should only happen if we
596 // need a reentrant plugin_load.
597 BX_ASSERT(current_plugin_context == plugin);
598 current_plugin_context = NULL;
599 return 1;
600 }
601
plugin_abort(plugin_t * plugin)602 void plugin_abort(plugin_t *plugin)
603 {
604 plugin_unload(plugin);
605 pluginlog->panic("loading plugin '%s' aborted", plugin->name);
606 }
607
608 #endif /* end of #if BX_PLUGINS */
609
610 /************************************************************************/
611 /* Plugin system: initialisation of plugins entry points */
612 /************************************************************************/
613
plugin_startup(void)614 void plugin_startup(void)
615 {
616 pluginRegisterIRQ = builtinRegisterIRQ;
617 pluginUnregisterIRQ = builtinUnregisterIRQ;
618
619 pluginSetHRQHackCallback = builtinSetHRQHackCallback;
620 pluginSetHRQ = builtinSetHRQ;
621
622 pluginRegisterIOReadHandler = builtinRegisterIOReadHandler;
623 pluginRegisterIOWriteHandler = builtinRegisterIOWriteHandler;
624
625 pluginUnregisterIOReadHandler = builtinUnregisterIOReadHandler;
626 pluginUnregisterIOWriteHandler = builtinUnregisterIOWriteHandler;
627
628 pluginRegisterIOReadHandlerRange = builtinRegisterIOReadHandlerRange;
629 pluginRegisterIOWriteHandlerRange = builtinRegisterIOWriteHandlerRange;
630
631 pluginUnregisterIOReadHandlerRange = builtinUnregisterIOReadHandlerRange;
632 pluginUnregisterIOWriteHandlerRange = builtinUnregisterIOWriteHandlerRange;
633
634 pluginRegisterDefaultIOReadHandler = builtinRegisterDefaultIOReadHandler;
635 pluginRegisterDefaultIOWriteHandler = builtinRegisterDefaultIOWriteHandler;
636
637 pluginlog = new logfunctions();
638 pluginlog->put("PLUGIN");
639 #if BX_PLUGINS
640 #if !defined(WIN32)
641 int status = lt_dlinit();
642 if (status != 0) {
643 BX_ERROR(("initialization error in ltdl library (for loading plugins)"));
644 BX_PANIC(("error message was: %s", lt_dlerror()));
645 }
646 #endif
647 plugins_search();
648 #endif
649 }
650
plugin_cleanup(void)651 void plugin_cleanup(void)
652 {
653 #if BX_PLUGINS
654 plugin_t *dead_plug;
655
656 while (plugins != NULL) {
657 if (plugins->loadtype != PLUGTYPE_NULL) {
658 plugin_unload(plugins);
659 }
660 delete [] plugins->name;
661
662 dead_plug = plugins;
663 plugins = plugins->next;
664 delete dead_plug;
665 }
666 #endif
667 }
668
669
670 /************************************************************************/
671 /* Plugin system: Device registration */
672 /************************************************************************/
673
pluginRegisterDeviceDevmodel(plugin_t * plugin,Bit16u type,bx_devmodel_c * devmodel,const char * name)674 void pluginRegisterDeviceDevmodel(plugin_t *plugin, Bit16u type, bx_devmodel_c *devmodel, const char *name)
675 {
676 device_t **devlist;
677
678 device_t *device = new device_t;
679
680 device->name = name;
681 BX_ASSERT(devmodel != NULL);
682 device->devmodel = devmodel;
683 device->plugin = plugin; // this can be NULL
684 device->next = NULL;
685 device->plugtype = type;
686
687 switch (type) {
688 case PLUGTYPE_CORE:
689 case PLUGTYPE_VGA:
690 devlist = &core_devices;
691 break;
692 case PLUGTYPE_STANDARD:
693 case PLUGTYPE_OPTIONAL:
694 default:
695 devlist = &devices;
696 break;
697 }
698
699 if (!*devlist) {
700 /* Empty list, this become the first entry. */
701 *devlist = device;
702 } else {
703 /* Non-empty list. Add to end. */
704 device_t *temp = *devlist;
705
706 while (temp->next)
707 temp = temp->next;
708
709 temp->next = device;
710 }
711 }
712
713 /************************************************************************/
714 /* Plugin system: Remove registered plugin device */
715 /************************************************************************/
716
pluginUnregisterDeviceDevmodel(const char * name,Bit16u type)717 void pluginUnregisterDeviceDevmodel(const char *name, Bit16u type)
718 {
719 device_t **devlist;
720 device_t *device, *prev = NULL;
721
722 switch (type) {
723 case PLUGTYPE_CORE:
724 case PLUGTYPE_VGA:
725 devlist = &core_devices;
726 break;
727 case PLUGTYPE_STANDARD:
728 case PLUGTYPE_OPTIONAL:
729 default:
730 devlist = &devices;
731 break;
732 }
733
734 for (device = *devlist; device; device = device->next) {
735 if (!strcmp(name, device->name)) {
736 if (prev == NULL) {
737 *devlist = device->next;
738 } else {
739 prev->next = device->next;
740 }
741 delete device;
742 break;
743 } else {
744 prev = device;
745 }
746 }
747 }
748
749 /************************************************************************/
750 /* Plugin system: Check if a plugin is loaded */
751 /************************************************************************/
752
pluginDevicePresent(const char * name)753 bool pluginDevicePresent(const char *name)
754 {
755 device_t *device;
756
757 for (device = devices; device; device = device->next)
758 {
759 if (!strcmp(name, device->name)) return 1;
760 }
761
762 return 0;
763 }
764
765 #if BX_PLUGINS
766 /************************************************************************/
767 /* Plugin system: Load one plugin */
768 /************************************************************************/
769
bx_load_plugin(const char * name,Bit16u type)770 bool bx_load_plugin(const char *name, Bit16u type)
771 {
772 plugin_t *plugin;
773
774 if (!strcmp(name, "*")) {
775 for (plugin = plugins; plugin; plugin = plugin->next) {
776 if (((type & plugin->type) != 0) && (plugin->loadtype == PLUGTYPE_NULL)) {
777 plugin_load(plugin->name, type);
778 }
779 }
780 return 1;
781 } else {
782 return plugin_load(name, type);
783 }
784 }
785
bx_unload_plugin(const char * name,bool devflag)786 bool bx_unload_plugin(const char *name, bool devflag)
787 {
788 plugin_t *plugin;
789 bool ret = 0;
790
791 for (plugin = plugins; plugin; plugin = plugin->next) {
792 if (!strcmp(plugin->name, name)) {
793 if (devflag) {
794 pluginUnregisterDeviceDevmodel(plugin->name, plugin->type);
795 }
796 ret = plugin_unload(plugin);
797 break;
798 }
799 }
800 return ret;
801 }
802
bx_unload_plugin_type(const char * name,Bit16u type)803 void bx_unload_plugin_type(const char *name, Bit16u type)
804 {
805 plugin_t *plugin;
806
807 for (plugin = plugins; plugin; plugin = plugin->next) {
808 if (!strcmp(plugin->name, name) && ((plugin->type & type) != 0)) {
809 plugin_unload(plugin);
810 break;
811 }
812 }
813 }
814
815 #endif /* end of #if BX_PLUGINS */
816
817 /*************************************************************************/
818 /* Plugin system: Execute init function of all registered plugin-devices */
819 /*************************************************************************/
820
bx_init_plugins()821 void bx_init_plugins()
822 {
823 device_t *device;
824
825 for (device = core_devices; device; device = device->next) {
826 pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name);
827 device->devmodel->init();
828 }
829 for (device = devices; device; device = device->next) {
830 if (device->plugtype == PLUGTYPE_STANDARD) {
831 pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name);
832 device->devmodel->init();
833 }
834 }
835 for (device = devices; device; device = device->next) {
836 if (device->plugtype == PLUGTYPE_OPTIONAL) {
837 pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name);
838 device->devmodel->init();
839 }
840 }
841 }
842
843 /**************************************************************************/
844 /* Plugin system: Execute reset function of all registered plugin-devices */
845 /**************************************************************************/
846
bx_reset_plugins(unsigned signal)847 void bx_reset_plugins(unsigned signal)
848 {
849 device_t *device;
850
851 for (device = core_devices; device; device = device->next) {
852 pluginlog->info("reset of '%s' plugin device by virtual method",device->name);
853 device->devmodel->reset(signal);
854 }
855 for (device = devices; device; device = device->next) {
856 if (device->plugtype == PLUGTYPE_STANDARD) {
857 pluginlog->info("reset of '%s' plugin device by virtual method",device->name);
858 device->devmodel->reset(signal);
859 }
860 }
861 for (device = devices; device; device = device->next) {
862 if (device->plugtype == PLUGTYPE_OPTIONAL) {
863 pluginlog->info("reset of '%s' plugin device by virtual method",device->name);
864 device->devmodel->reset(signal);
865 }
866 }
867 }
868
869 /*******************************************************/
870 /* Plugin system: Unload all registered plugin-devices */
871 /*******************************************************/
872
bx_unload_plugins()873 void bx_unload_plugins()
874 {
875 device_t *device, *next;
876
877 // unload non-core plugins first
878 device = devices;
879 while (device != NULL) {
880 if (device->plugin != NULL) {
881 #if BX_PLUGINS
882 bx_unload_plugin(device->name, 0);
883 #endif
884 } else {
885 #if !BX_PLUGINS
886 if (!bx_unload_opt_plugin(device->name, 0)) {
887 delete device->devmodel;
888 }
889 #endif
890 }
891 next = device->next;
892 delete device;
893 device = next;
894 }
895 devices = NULL;
896
897 // now it's safe to unload core plugins
898 device = core_devices;
899 while (device != NULL) {
900 if (device->plugin != NULL) {
901 #if BX_PLUGINS
902 bx_unload_plugin(device->name, 0);
903 #endif
904 } else {
905 delete device->devmodel;
906 }
907 next = device->next;
908 delete device;
909 device = next;
910 }
911 core_devices = NULL;
912 }
913
914 /**************************************************************************/
915 /* Plugin system: Register device state of all registered plugin-devices */
916 /**************************************************************************/
917
bx_plugins_register_state()918 void bx_plugins_register_state()
919 {
920 device_t *device;
921
922 for (device = core_devices; device; device = device->next) {
923 pluginlog->info("register state of '%s' plugin device by virtual method",device->name);
924 device->devmodel->register_state();
925 }
926 for (device = devices; device; device = device->next) {
927 pluginlog->info("register state of '%s' plugin device by virtual method",device->name);
928 device->devmodel->register_state();
929 }
930 }
931
932 /***************************************************************************/
933 /* Plugin system: Execute code after restoring state of all plugin devices */
934 /***************************************************************************/
935
bx_plugins_after_restore_state()936 void bx_plugins_after_restore_state()
937 {
938 device_t *device;
939
940 for (device = core_devices; device; device = device->next) {
941 device->devmodel->after_restore_state();
942 }
943 for (device = devices; device; device = device->next) {
944 if (device->plugtype == PLUGTYPE_STANDARD) {
945 device->devmodel->after_restore_state();
946 }
947 }
948 for (device = devices; device; device = device->next) {
949 if (device->plugtype == PLUGTYPE_OPTIONAL) {
950 device->devmodel->after_restore_state();
951 }
952 }
953 }
954
955 #if !BX_PLUGINS
956
957 // Special code for handling modules when plugin support is turned off.
958
959 #define BUILTIN_OPT_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_OPTIONAL, 0, lib##mod##_plugin_entry, 0}
960 #define BUILTIN_OPTPCI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_OPTIONAL, PLUGFLAG_PCI, lib##mod##_plugin_entry, 0}
961 #define BUILTIN_VGA_PLUGIN_ENTRY(mod, t, f) {#mod, PLUGTYPE_VGA | t, f, lib##mod##_plugin_entry, 0}
962 #define BUILTIN_CI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_CI, 0, lib##mod##_plugin_entry, 0}
963 #define BUILTIN_GUI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_GUI, 0, lib##mod##_gui_plugin_entry, 0}
964 #define BUILTIN_GUICI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_GUI | PLUGTYPE_CI, 0, lib##mod##_gui_plugin_entry, 0}
965 #define BUILTIN_IMG_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_IMG, 0, lib##mod##_img_plugin_entry, 0}
966 #define BUILTIN_NET_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_NET, 0, libeth_##mod##_plugin_entry, 0}
967 #define BUILTIN_SND_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_SND, 0, libsound##mod##_plugin_entry, 0}
968 #define BUILTIN_USB_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_USB, 0, lib##mod##_plugin_entry, 0}
969
970 plugin_t bx_builtin_plugins[] = {
971 #if BX_USE_TEXTCONFIG
972 BUILTIN_CI_PLUGIN_ENTRY(textconfig),
973 #endif
974 #if BX_USE_WIN32CONFIG
975 BUILTIN_CI_PLUGIN_ENTRY(win32config),
976 #endif
977 #if BX_WITH_AMIGAOS
978 BUILTIN_GUI_PLUGIN_ENTRY(amigaos),
979 #endif
980 #if BX_WITH_CARBON
981 BUILTIN_GUI_PLUGIN_ENTRY(carbon),
982 #endif
983 #if BX_WITH_MACOS
984 BUILTIN_GUI_PLUGIN_ENTRY(macos),
985 #endif
986 #if BX_WITH_NOGUI
987 BUILTIN_GUI_PLUGIN_ENTRY(nogui),
988 #endif
989 #if BX_WITH_RFB
990 BUILTIN_GUI_PLUGIN_ENTRY(rfb),
991 #endif
992 #if BX_WITH_SDL
993 BUILTIN_GUI_PLUGIN_ENTRY(sdl),
994 #endif
995 #if BX_WITH_SDL2
996 BUILTIN_GUI_PLUGIN_ENTRY(sdl2),
997 #endif
998 #if BX_WITH_TERM
999 BUILTIN_GUI_PLUGIN_ENTRY(term),
1000 #endif
1001 #if BX_WITH_VNCSRV
1002 BUILTIN_GUI_PLUGIN_ENTRY(vncsrv),
1003 #endif
1004 #if BX_WITH_WIN32
1005 BUILTIN_GUI_PLUGIN_ENTRY(win32),
1006 #endif
1007 #if BX_WITH_WX
1008 BUILTIN_GUICI_PLUGIN_ENTRY(wx),
1009 #endif
1010 #if BX_WITH_X11
1011 BUILTIN_GUI_PLUGIN_ENTRY(x),
1012 #endif
1013 BUILTIN_VGA_PLUGIN_ENTRY(vga, 0, PLUGFLAG_PCI),
1014 #if BX_SUPPORT_CLGD54XX
1015 BUILTIN_VGA_PLUGIN_ENTRY(svga_cirrus, 0, PLUGFLAG_PCI),
1016 #endif
1017 #if BX_SUPPORT_VOODOO
1018 BUILTIN_VGA_PLUGIN_ENTRY(voodoo, PLUGTYPE_OPTIONAL, PLUGFLAG_PCI),
1019 #endif
1020 BUILTIN_OPT_PLUGIN_ENTRY(unmapped),
1021 BUILTIN_OPT_PLUGIN_ENTRY(biosdev),
1022 BUILTIN_OPT_PLUGIN_ENTRY(speaker),
1023 BUILTIN_OPT_PLUGIN_ENTRY(extfpuirq),
1024 BUILTIN_OPT_PLUGIN_ENTRY(parallel),
1025 BUILTIN_OPT_PLUGIN_ENTRY(serial),
1026 #if BX_SUPPORT_BUSMOUSE
1027 BUILTIN_OPT_PLUGIN_ENTRY(busmouse),
1028 #endif
1029 #if BX_SUPPORT_E1000
1030 BUILTIN_OPTPCI_PLUGIN_ENTRY(e1000),
1031 #endif
1032 #if BX_SUPPORT_ES1370
1033 BUILTIN_OPTPCI_PLUGIN_ENTRY(es1370),
1034 #endif
1035 #if BX_SUPPORT_GAMEPORT
1036 BUILTIN_OPT_PLUGIN_ENTRY(gameport),
1037 #endif
1038 #if BX_SUPPORT_IODEBUG
1039 BUILTIN_OPT_PLUGIN_ENTRY(iodebug),
1040 #endif
1041 #if BX_SUPPORT_NE2K
1042 BUILTIN_OPTPCI_PLUGIN_ENTRY(ne2k),
1043 #endif
1044 #if BX_SUPPORT_PCIDEV
1045 BUILTIN_OPTPCI_PLUGIN_ENTRY(pcidev),
1046 #endif
1047 #if BX_SUPPORT_PCIPNIC
1048 BUILTIN_OPTPCI_PLUGIN_ENTRY(pcipnic),
1049 #endif
1050 #if BX_SUPPORT_SB16
1051 BUILTIN_OPT_PLUGIN_ENTRY(sb16),
1052 #endif
1053 #if BX_SUPPORT_USB_UHCI
1054 BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_uhci),
1055 #endif
1056 #if BX_SUPPORT_USB_OHCI
1057 BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_ohci),
1058 #endif
1059 #if BX_SUPPORT_USB_EHCI
1060 BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_ehci),
1061 #endif
1062 #if BX_SUPPORT_USB_XHCI
1063 BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_xhci),
1064 #endif
1065 #if BX_SUPPORT_SOUNDLOW
1066 BUILTIN_SND_PLUGIN_ENTRY(dummy),
1067 BUILTIN_SND_PLUGIN_ENTRY(file),
1068 #if BX_HAVE_SOUND_ALSA
1069 BUILTIN_SND_PLUGIN_ENTRY(alsa),
1070 #endif
1071 #if BX_HAVE_SOUND_OSS
1072 BUILTIN_SND_PLUGIN_ENTRY(oss),
1073 #endif
1074 #if BX_HAVE_SOUND_OSX
1075 BUILTIN_SND_PLUGIN_ENTRY(osx),
1076 #endif
1077 #if BX_HAVE_SOUND_SDL
1078 BUILTIN_SND_PLUGIN_ENTRY(sdl),
1079 #endif
1080 #if BX_HAVE_SOUND_WIN
1081 BUILTIN_SND_PLUGIN_ENTRY(win),
1082 #endif
1083 #endif
1084 #if BX_NETWORKING
1085 BUILTIN_NET_PLUGIN_ENTRY(null),
1086 BUILTIN_NET_PLUGIN_ENTRY(vnet),
1087 #if BX_NETMOD_FBSD
1088 BUILTIN_NET_PLUGIN_ENTRY(fbsd),
1089 #endif
1090 #if BX_NETMOD_LINUX
1091 BUILTIN_NET_PLUGIN_ENTRY(linux),
1092 #endif
1093 #if BX_NETMOD_SLIRP
1094 BUILTIN_NET_PLUGIN_ENTRY(slirp),
1095 #endif
1096 #if BX_NETMOD_SOCKET
1097 BUILTIN_NET_PLUGIN_ENTRY(socket),
1098 #endif
1099 #if BX_NETMOD_TAP
1100 BUILTIN_NET_PLUGIN_ENTRY(tap),
1101 #endif
1102 #if BX_NETMOD_TUNTAP
1103 BUILTIN_NET_PLUGIN_ENTRY(tuntap),
1104 #endif
1105 #if BX_NETMOD_VDE
1106 BUILTIN_NET_PLUGIN_ENTRY(vde),
1107 #endif
1108 #if BX_NETMOD_WIN32
1109 BUILTIN_NET_PLUGIN_ENTRY(win32),
1110 #endif
1111 #endif
1112 #if BX_SUPPORT_PCIUSB
1113 BUILTIN_USB_PLUGIN_ENTRY(usb_floppy),
1114 BUILTIN_USB_PLUGIN_ENTRY(usb_hid),
1115 BUILTIN_USB_PLUGIN_ENTRY(usb_hub),
1116 BUILTIN_USB_PLUGIN_ENTRY(usb_msd),
1117 BUILTIN_USB_PLUGIN_ENTRY(usb_printer),
1118 #endif
1119 BUILTIN_IMG_PLUGIN_ENTRY(vmware3),
1120 BUILTIN_IMG_PLUGIN_ENTRY(vmware4),
1121 BUILTIN_IMG_PLUGIN_ENTRY(vbox),
1122 BUILTIN_IMG_PLUGIN_ENTRY(vpc),
1123 BUILTIN_IMG_PLUGIN_ENTRY(vvfat),
1124 {"NULL", PLUGTYPE_NULL, 0, NULL, 0}
1125 };
1126
bx_get_plugins_count_np(Bit16u type)1127 Bit8u bx_get_plugins_count_np(Bit16u type)
1128 {
1129 int i = 0;
1130 Bit8u count = 0;
1131
1132 while (strcmp(bx_builtin_plugins[i].name, "NULL")) {
1133 if ((type & bx_builtin_plugins[i].type) != 0)
1134 count++;
1135 i++;
1136 }
1137 return count;
1138 }
1139
bx_get_plugin_name_np(Bit16u type,Bit8u index)1140 const char* bx_get_plugin_name_np(Bit16u type, Bit8u index)
1141 {
1142 int i = 0;
1143 Bit8u count = 0;
1144
1145 while (strcmp(bx_builtin_plugins[i].name, "NULL")) {
1146 if ((type & bx_builtin_plugins[i].type) != 0) {
1147 if (count == index)
1148 return bx_builtin_plugins[i].name;
1149 count++;
1150 }
1151 i++;
1152 }
1153 return NULL;
1154 }
1155
bx_get_plugin_flags_np(Bit16u type,Bit8u index)1156 Bit8u bx_get_plugin_flags_np(Bit16u type, Bit8u index)
1157 {
1158 int i = 0;
1159 Bit8u count = 0;
1160
1161 while (strcmp(bx_builtin_plugins[i].name, "NULL")) {
1162 if ((type & bx_builtin_plugins[i].type) != 0) {
1163 if (count == index)
1164 return bx_builtin_plugins[i].flags;
1165 count++;
1166 }
1167 i++;
1168 }
1169 return 0;
1170 }
1171
bx_load_plugin_np(const char * name,Bit16u type)1172 int bx_load_plugin_np(const char *name, Bit16u type)
1173 {
1174 int i = 0;
1175 while (strcmp(bx_builtin_plugins[i].name, "NULL")) {
1176 if ((!strcmp(name, bx_builtin_plugins[i].name)) &&
1177 ((type & bx_builtin_plugins[i].type) != 0)) {
1178 if (bx_builtin_plugins[i].initialized == 0) {
1179 bx_builtin_plugins[i].loadtype = type;
1180 bx_builtin_plugins[i].plugin_entry(NULL, type, PLUGIN_INIT);
1181 bx_builtin_plugins[i].initialized = 1;
1182 }
1183 return 1;
1184 }
1185 i++;
1186 }
1187 return 0;
1188 }
1189
bx_unload_opt_plugin(const char * name,bool devflag)1190 int bx_unload_opt_plugin(const char *name, bool devflag)
1191 {
1192 int i = 0;
1193 while (strcmp(bx_builtin_plugins[i].name, "NULL")) {
1194 if ((!strcmp(name, bx_builtin_plugins[i].name)) &&
1195 ((bx_builtin_plugins[i].type == PLUGTYPE_OPTIONAL) ||
1196 (bx_builtin_plugins[i].type == PLUGTYPE_VGA))) {
1197 if (bx_builtin_plugins[i].initialized == 1) {
1198 if (devflag) {
1199 pluginUnregisterDeviceDevmodel(bx_builtin_plugins[i].name,
1200 bx_builtin_plugins[i].type);
1201 }
1202 bx_builtin_plugins[i].plugin_entry(NULL, bx_builtin_plugins[i].loadtype, PLUGIN_FINI);
1203 bx_builtin_plugins[i].loadtype = PLUGTYPE_NULL;
1204 bx_builtin_plugins[i].initialized = 0;
1205 }
1206 return 1;
1207 }
1208 i++;
1209 }
1210 return 0;
1211 }
1212
1213 #endif
1214
1215 }
1216