/[gxemul]/upstream/0.3.6/src/device.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.6/src/device.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 9511 byte(s)
0.3.6
1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: device.c,v 1.16 2005/08/10 22:25:50 debug Exp $
29 *
30 * Device registry framework.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "device.h"
38 #include "misc.h"
39
40
41 static struct device_entry *device_entries = NULL;
42 static int device_entries_sorted = 0;
43 static int n_device_entries = 0;
44 static int device_exit_on_error = 1;
45
46
47 /*
48 * device_entry_compar():
49 *
50 * Internal function, used by sort_entries().
51 */
52 static int device_entry_compar(const void *a, const void *b)
53 {
54 struct device_entry *pa = (struct device_entry *) a;
55 struct device_entry *pb = (struct device_entry *) b;
56
57 return strcmp(pa->name, pb->name);
58 }
59
60
61 /*
62 * sort_entries():
63 *
64 * Internal function. Sorts the device_entries array in alphabetic order.
65 */
66 static void sort_entries(void)
67 {
68 qsort(device_entries, n_device_entries, sizeof(struct device_entry),
69 device_entry_compar);
70
71 device_entries_sorted = 1;
72 }
73
74
75 /*
76 * device_register():
77 *
78 * Registers a device. The device is added to the end of the device_entries
79 * array, and the sorted flag is set to zero.
80 *
81 * NOTE: It would be a bad thing if two devices had the same name. However,
82 * that isn't checked here, it is up to the caller!
83 *
84 * Return value is 1 if the device was registered, 0 otherwise.
85 */
86 int device_register(char *name, int (*initf)(struct devinit *))
87 {
88 device_entries = realloc(device_entries, sizeof(struct device_entry)
89 * (n_device_entries + 1));
90 if (device_entries == NULL) {
91 fprintf(stderr, "device_register(): out of memory\n");
92 exit(1);
93 }
94
95 memset(&device_entries[n_device_entries], 0,
96 sizeof(struct device_entry));
97
98 device_entries[n_device_entries].name = strdup(name);
99 device_entries[n_device_entries].initf = initf;
100
101 device_entries_sorted = 0;
102 n_device_entries ++;
103 return 1;
104 }
105
106
107 /*
108 * device_lookup():
109 *
110 * Lookup a device name by scanning the device_entries array (as a binary
111 * search tree).
112 *
113 * Return value is a pointer to the device_entry on success, or a NULL pointer
114 * if there was no such device.
115 */
116 struct device_entry *device_lookup(char *name)
117 {
118 int i, step, r, do_return = 0;
119
120 if (name == NULL) {
121 fprintf(stderr, "device_lookup(): NULL ptr\n");
122 exit(1);
123 }
124
125 if (!device_entries_sorted)
126 sort_entries();
127
128 if (n_device_entries == 0)
129 return NULL;
130
131 i = n_device_entries / 2;
132 step = i/2 + 1;
133
134 for (;;) {
135 if (i < 0)
136 i = 0;
137 if (i >= n_device_entries)
138 i = n_device_entries - 1;
139
140 /* printf("device_lookup(): i=%i step=%i\n", i, step);
141 printf(" name='%s', '%s'\n", name,
142 device_entries[i].name); */
143
144 r = strcmp(name, device_entries[i].name);
145
146 if (r < 0) {
147 /* Go left: */
148 i -= step;
149 if (step == 0)
150 i --;
151 } else if (r > 0) {
152 /* Go right: */
153 i += step;
154 if (step == 0)
155 i ++;
156 } else {
157 /* Found it! */
158 return &device_entries[i];
159 }
160
161 if (do_return)
162 return NULL;
163
164 if (step == 0)
165 do_return = 1;
166
167 if (step & 1)
168 step = (step/2) + 1;
169 else
170 step /= 2;
171 }
172 }
173
174
175 /*
176 * device_unregister():
177 *
178 * Unregisters a device.
179 *
180 * Return value is 1 if a device was unregistered, 0 otherwise.
181 */
182 int device_unregister(char *name)
183 {
184 ssize_t i;
185 struct device_entry *p = device_lookup(name);
186
187 if (p == NULL) {
188 fatal("device_unregister(): no such device (\"%s\")\n", name);
189 return 0;
190 }
191
192 i = (size_t)p - (size_t)device_entries;
193 i /= sizeof(struct device_entry);
194
195 free(device_entries[i].name);
196 device_entries[i].name = NULL;
197
198 if (i == n_device_entries-1) {
199 /* Do nothing if we're removing the last array element. */
200 } else {
201 /* Remove array element i by copying the last element
202 to i's position: */
203 device_entries[i] = device_entries[n_device_entries-1];
204
205 /* The array is not sorted anymore: */
206 device_entries_sorted = 0;
207 }
208
209 n_device_entries --;
210
211 /* TODO: realloc? */
212 return 1;
213 }
214
215
216 /*
217 * device_add():
218 *
219 * Add a device to a machine. For example: "kn210 addr=0x12340000" adds a
220 * device called "kn210" at a specific address.
221 *
222 * TODO: This function is quite ugly, and should be cleaned up.
223 */
224 void *device_add(struct machine *machine, char *name_and_params)
225 {
226 struct device_entry *p;
227 struct devinit devinit;
228 char *s2, *s3;
229 size_t len;
230
231 memset(&devinit, 0, sizeof(struct devinit));
232 devinit.machine = machine;
233
234 /* Default values: */
235 devinit.addr_mult = 1;
236 devinit.in_use = 1;
237
238 /* Get the device name first: */
239 s2 = name_and_params;
240 while (s2[0] != ',' && s2[0] != ' ' && s2[0] != '\0')
241 s2 ++;
242
243 len = (size_t)s2 - (size_t)name_and_params;
244 devinit.name = malloc(len + 1);
245 if (devinit.name == NULL) {
246 fprintf(stderr, "device_add(): out of memory\n");
247 exit(1);
248 }
249 memcpy(devinit.name, name_and_params, len);
250 devinit.name[len] = '\0';
251
252 p = device_lookup(devinit.name);
253 if (p == NULL) {
254 fatal("no such device (\"%s\")\n", devinit.name);
255 if (device_exit_on_error)
256 exit(1);
257 else
258 goto return_fail;
259 }
260
261 /* Get params from name_and_params: */
262 while (*s2 != '\0') {
263 /* Skip spaces, commas, and semicolons: */
264 while (*s2 == ' ' || *s2 == ',' || *s2 == ';')
265 s2 ++;
266
267 if (*s2 == '\0')
268 break;
269
270 /* s2 now points to the next param. eg "addr=1234" */
271
272 /* Get a word (until there is a '=' sign): */
273 s3 = s2;
274 while (*s3 != '=' && *s3 != '\0')
275 s3 ++;
276 if (s3 == s2) {
277 fatal("weird param: %s\n", s2);
278 if (device_exit_on_error)
279 exit(1);
280 else
281 goto return_fail;
282 }
283 s3 ++;
284 /* s3 now points to the parameter value ("1234") */
285
286 if (strncmp(s2, "addr=", 5) == 0) {
287 devinit.addr = mystrtoull(s3, NULL, 0);
288 } else if (strncmp(s2, "len=", 4) == 0) {
289 devinit.len = mystrtoull(s3, NULL, 0);
290 } else if (strncmp(s2, "addr_mult=", 10) == 0) {
291 devinit.addr_mult = mystrtoull(s3, NULL, 0);
292 } else if (strncmp(s2, "irq=", 4) == 0) {
293 devinit.irq_nr = mystrtoull(s3, NULL, 0);
294 } else if (strncmp(s2, "in_use=", 7) == 0) {
295 devinit.in_use = mystrtoull(s3, NULL, 0);
296 } else if (strncmp(s2, "name2=", 6) == 0) {
297 char *h = s2 + 6;
298 size_t len = 0;
299 while (*h && *h != ' ')
300 h++, len++;
301 devinit.name2 = malloc(len + 1);
302 if (devinit.name2 == NULL) {
303 fprintf(stderr, "out of memory\n");
304 exit(1);
305 }
306 snprintf(devinit.name2, len + 1, s2 + 6);
307 } else {
308 fatal("unknown param: %s\n", s2);
309 if (device_exit_on_error)
310 exit(1);
311 else
312 goto return_fail;
313 }
314
315 /* skip to the next param: */
316 s2 = s3;
317 while (*s2 != '\0' && *s2 != ' ' && *s2 != ',' && *s2 != ';')
318 s2 ++;
319 }
320
321
322 /*
323 * Call the init function for this device:
324 */
325
326 devinit.return_ptr = NULL;
327
328 if (!p->initf(&devinit)) {
329 fatal("error adding device (\"%s\")\n", name_and_params);
330 if (device_exit_on_error)
331 exit(1);
332 else
333 goto return_fail;
334 }
335
336 free(devinit.name);
337 return devinit.return_ptr;
338
339 return_fail:
340 free(devinit.name);
341 return NULL;
342 }
343
344
345 /*
346 * device_dumplist():
347 *
348 * Dump a list of all registered devices. (If the list is not sorted when
349 * this function is called, it is implicitly sorted.)
350 */
351 void device_dumplist(void)
352 {
353 int i;
354
355 if (!device_entries_sorted)
356 sort_entries();
357
358 for (i=0; i<n_device_entries; i++) {
359 debug(" %s", device_entries[i].name);
360
361 /* TODO: flags? */
362
363 debug("\n");
364 }
365 }
366
367
368 /*
369 * device_set_exit_on_error():
370 *
371 * This function selects the behaviour of the emulator when a device is not
372 * found. During startup, it is nicest to abort the whole emulator session,
373 * but if a device addition is attempted from within the debugger, then it is
374 * nicer to just print a warning and continue.
375 */
376 void device_set_exit_on_error(int exit_on_error)
377 {
378 device_exit_on_error = exit_on_error;
379 }
380
381
382 /*
383 * device_init():
384 *
385 * Initialize the device registry, and call autodev_init() to automatically
386 * add all normal devices (from the src/devices/ directory).
387 *
388 * This function should be called before any other device_*() function is used.
389 */
390 void device_init(void)
391 {
392 device_entries = NULL;
393 device_entries_sorted = 0;
394 n_device_entries = 0;
395
396 autodev_init();
397 }
398

  ViewVC Help
Powered by ViewVC 1.1.26