/[gxemul]/upstream/0.4.3/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.4.3/src/device.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (show annotations)
Mon Oct 8 16:21:06 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 11407 byte(s)
0.4.3
1 /*
2 * Copyright (C) 2005-2006 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.26 2006/04/06 19:17:37 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 "memory.h"
39 #include "misc.h"
40
41
42 static struct device_entry *device_entries = NULL;
43 static int device_entries_sorted = 0;
44 static int n_device_entries = 0;
45 static int device_exit_on_error = 1;
46
47 static struct pci_entry *pci_entries = NULL;
48 static int n_pci_entries = 0;
49
50
51 /*
52 * device_entry_compar():
53 *
54 * Internal function, used by sort_entries().
55 */
56 static int device_entry_compar(const void *a, const void *b)
57 {
58 struct device_entry *pa = (struct device_entry *) a;
59 struct device_entry *pb = (struct device_entry *) b;
60
61 return strcmp(pa->name, pb->name);
62 }
63
64
65 /*
66 * sort_entries():
67 *
68 * Internal function. Sorts the device_entries array in alphabetic order.
69 */
70 static void sort_entries(void)
71 {
72 qsort(device_entries, n_device_entries, sizeof(struct device_entry),
73 device_entry_compar);
74
75 device_entries_sorted = 1;
76 }
77
78
79 /*
80 * device_register():
81 *
82 * Registers a device. The device is added to the end of the device_entries
83 * array, and the sorted flag is set to zero.
84 *
85 * NOTE: It would be a bad thing if two devices had the same name. However,
86 * that isn't checked here, it is up to the caller!
87 *
88 * Return value is 1 if the device was registered, 0 otherwise.
89 */
90 int device_register(char *name, int (*initf)(struct devinit *))
91 {
92 device_entries = realloc(device_entries, sizeof(struct device_entry)
93 * (n_device_entries + 1));
94 if (device_entries == NULL) {
95 fprintf(stderr, "device_register(): out of memory\n");
96 exit(1);
97 }
98
99 memset(&device_entries[n_device_entries], 0,
100 sizeof(struct device_entry));
101
102 device_entries[n_device_entries].name = strdup(name);
103 device_entries[n_device_entries].initf = initf;
104
105 device_entries_sorted = 0;
106 n_device_entries ++;
107 return 1;
108 }
109
110
111 /*
112 * pci_register():
113 *
114 * Registers a pci device. The pci device is added to the pci_entries array.
115 *
116 * Return value is 1 if the pci device was registered. If it was not
117 * added, this function does not return.
118 */
119 int pci_register(char *name, void (*initf)(struct machine *, struct memory *,
120 struct pci_device *))
121 {
122 pci_entries = realloc(pci_entries, sizeof(struct pci_entry)
123 * (n_pci_entries + 1));
124 if (pci_entries == NULL) {
125 fprintf(stderr, "pci_register(): out of memory\n");
126 exit(1);
127 }
128
129 memset(&pci_entries[n_pci_entries], 0, sizeof(struct pci_entry));
130
131 pci_entries[n_pci_entries].name = strdup(name);
132 pci_entries[n_pci_entries].initf = initf;
133 n_pci_entries ++;
134 return 1;
135 }
136
137
138 /*
139 * pci_lookup_initf():
140 *
141 * Find a pci device init function by scanning the pci_entries array.
142 *
143 * Return value is a function pointer, or NULL if the name was not found.
144 */
145 void (*pci_lookup_initf(const char *name))(struct machine *machine,
146 struct memory *mem, struct pci_device *pd)
147 {
148 int i;
149
150 if (name == NULL) {
151 fprintf(stderr, "pci_lookup_initf(): name = NULL\n");
152 exit(1);
153 }
154
155 for (i=0; i<n_pci_entries; i++)
156 if (strcmp(name, pci_entries[i].name) == 0)
157 return pci_entries[i].initf;
158 return NULL;
159 }
160
161
162 /*
163 * device_lookup():
164 *
165 * Lookup a device name by scanning the device_entries array (as a binary
166 * search tree).
167 *
168 * Return value is a pointer to the device_entry on success, or a NULL pointer
169 * if there was no such device.
170 */
171 struct device_entry *device_lookup(char *name)
172 {
173 int hi, lo;
174
175 if (name == NULL) {
176 fprintf(stderr, "device_lookup(): NULL ptr\n");
177 exit(1);
178 }
179
180 if (!device_entries_sorted)
181 sort_entries();
182
183 if (n_device_entries == 0)
184 return NULL;
185
186 lo = 0; hi = n_device_entries - 1;
187
188 while (lo <= hi) {
189 int r, i = (lo + hi) / 2;
190
191 /* printf("device_lookup(): i=%i (lo=%i hi=%i)\n", i, lo, hi);
192 printf(" name='%s', '%s'\n", name,
193 device_entries[i].name); */
194
195 r = strcmp(name, device_entries[i].name);
196 if (r == 0) {
197 /* Found it! */
198 return &device_entries[i];
199 }
200
201 /* Try left or right half: */
202 if (r < 0)
203 hi = i - 1;
204 if (r > 0)
205 lo = i + 1;
206 }
207
208 return NULL;
209 }
210
211
212 /*
213 * device_unregister():
214 *
215 * Unregisters a device.
216 *
217 * Return value is 1 if a device was unregistered, 0 otherwise.
218 */
219 int device_unregister(char *name)
220 {
221 ssize_t i;
222 struct device_entry *p = device_lookup(name);
223
224 if (p == NULL) {
225 fatal("device_unregister(): no such device (\"%s\")\n", name);
226 return 0;
227 }
228
229 i = (size_t)p - (size_t)device_entries;
230 i /= sizeof(struct device_entry);
231
232 free(device_entries[i].name);
233 device_entries[i].name = NULL;
234
235 if (i == n_device_entries-1) {
236 /* Do nothing if we're removing the last array element. */
237 } else {
238 /* Remove array element i by copying the last element
239 to i's position: */
240 device_entries[i] = device_entries[n_device_entries-1];
241
242 /* The array is not sorted anymore: */
243 device_entries_sorted = 0;
244 }
245
246 n_device_entries --;
247
248 /* TODO: realloc? */
249 return 1;
250 }
251
252
253 /*
254 * device_add():
255 *
256 * Add a device to a machine. For example: "kn210 addr=0x12340000" adds a
257 * device called "kn210" at a specific address.
258 *
259 * TODO: This function is quite ugly, and should be cleaned up.
260 * name_and_params should be const.
261 */
262 void *device_add(struct machine *machine, char *name_and_params)
263 {
264 struct device_entry *p;
265 struct devinit devinit;
266 char *s2, *s3;
267 size_t len;
268 int quoted;
269
270 memset(&devinit, 0, sizeof(struct devinit));
271 devinit.machine = machine;
272
273 /* Default values: */
274 devinit.addr_mult = 1;
275 devinit.in_use = 1;
276
277 /* Get the device name first: */
278 s2 = name_and_params;
279 while (s2[0] != ',' && s2[0] != ' ' && s2[0] != '\0')
280 s2 ++;
281
282 len = (size_t)s2 - (size_t)name_and_params;
283 devinit.name = malloc(len + 1);
284 if (devinit.name == NULL) {
285 fprintf(stderr, "device_add(): out of memory\n");
286 exit(1);
287 }
288 memcpy(devinit.name, name_and_params, len);
289 devinit.name[len] = '\0';
290 devinit.dma_irq_nr = -1;
291
292 p = device_lookup(devinit.name);
293 if (p == NULL) {
294 fatal("no such device (\"%s\")\n", devinit.name);
295 if (device_exit_on_error)
296 exit(1);
297 else
298 goto return_fail;
299 }
300
301 /* Get params from name_and_params: */
302 while (*s2 != '\0') {
303 /* Skip spaces, commas, and semicolons: */
304 while (*s2 == ' ' || *s2 == ',' || *s2 == ';')
305 s2 ++;
306
307 if (*s2 == '\0')
308 break;
309
310 /* s2 now points to the next param. eg "addr=1234" */
311
312 /* Get a word (until there is a '=' sign): */
313 s3 = s2;
314 while (*s3 != '=' && *s3 != '\0')
315 s3 ++;
316 if (s3 == s2) {
317 fatal("weird param: %s\n", s2);
318 if (device_exit_on_error)
319 exit(1);
320 else
321 goto return_fail;
322 }
323 s3 ++;
324 /* s3 now points to the parameter value ("1234") */
325
326 if (strncmp(s2, "addr=", 5) == 0) {
327 devinit.addr = mystrtoull(s3, NULL, 0);
328 } else if (strncmp(s2, "addr2=", 6) == 0) {
329 devinit.addr2 = mystrtoull(s3, NULL, 0);
330 } else if (strncmp(s2, "len=", 4) == 0) {
331 devinit.len = mystrtoull(s3, NULL, 0);
332 } else if (strncmp(s2, "addr_mult=", 10) == 0) {
333 devinit.addr_mult = mystrtoull(s3, NULL, 0);
334 } else if (strncmp(s2, "pci_little_endian=", 18) == 0) {
335 devinit.pci_little_endian = mystrtoull(s3, NULL, 0);
336 switch (devinit.pci_little_endian) {
337 case 0: break;
338 case 1: devinit.pci_little_endian =
339 MEM_PCI_LITTLE_ENDIAN;
340 break;
341 default:fatal("Bad pci_little_endian value.\n");
342 exit(1);
343 }
344 } else if (strncmp(s2, "irq=", 4) == 0) {
345 devinit.irq_nr = mystrtoull(s3, NULL, 0);
346 } else if (strncmp(s2, "dma_irq=", 8) == 0) {
347 devinit.dma_irq_nr = mystrtoull(s3, NULL, 0);
348 } else if (strncmp(s2, "in_use=", 7) == 0) {
349 devinit.in_use = mystrtoull(s3, NULL, 0);
350 } else if (strncmp(s2, "name2=", 6) == 0) {
351 char *h = s2 + 6;
352 size_t len = 0;
353 quoted = 0;
354 while (*h) {
355 if (*h == '\'')
356 quoted = !quoted;
357 h++, len++;
358 if (!quoted && *h == ' ')
359 break;
360 }
361 devinit.name2 = malloc(len + 1);
362 if (devinit.name2 == NULL) {
363 fprintf(stderr, "out of memory\n");
364 exit(1);
365 }
366 h = s2 + 6;
367 if (*h == '\'')
368 len -= 2, h++;
369 snprintf(devinit.name2, len + 1, h);
370 } else {
371 fatal("unknown param: %s\n", s2);
372 if (device_exit_on_error)
373 exit(1);
374 else
375 goto return_fail;
376 }
377
378 /* skip to the next param: */
379 s2 = s3;
380 quoted = 0;
381 while (*s2 != '\0' && (*s2 != ' ' || quoted) &&
382 *s2 != ',' && *s2 != ';') {
383 if (*s2 == '\'')
384 quoted = !quoted;
385 s2 ++;
386 }
387 }
388
389
390 /*
391 * Call the init function for this device:
392 */
393
394 devinit.return_ptr = NULL;
395
396 if (!p->initf(&devinit)) {
397 fatal("error adding device (\"%s\")\n", name_and_params);
398 if (device_exit_on_error)
399 exit(1);
400 else
401 goto return_fail;
402 }
403
404 free(devinit.name);
405 return devinit.return_ptr;
406
407 return_fail:
408 free(devinit.name);
409 return NULL;
410 }
411
412
413 /*
414 * device_dumplist():
415 *
416 * Dump a list of all registered devices. (If the list is not sorted when
417 * this function is called, it is implicitly sorted.)
418 */
419 void device_dumplist(void)
420 {
421 int i;
422
423 if (!device_entries_sorted)
424 sort_entries();
425
426 for (i=0; i<n_device_entries; i++) {
427 debug(" %s", device_entries[i].name);
428
429 /* TODO: flags? */
430
431 debug("\n");
432 }
433 }
434
435
436 /*
437 * device_set_exit_on_error():
438 *
439 * This function selects the behaviour of the emulator when a device is not
440 * found. During startup, it is nicest to abort the whole emulator session,
441 * but if a device addition is attempted from within the debugger, then it is
442 * nicer to just print a warning and continue.
443 */
444 void device_set_exit_on_error(int exit_on_error)
445 {
446 device_exit_on_error = exit_on_error;
447 }
448
449
450 /*
451 * device_init():
452 *
453 * Initialize the device registry, and call autodev_init() to automatically
454 * add all normal devices (from the src/devices/ directory).
455 *
456 * This function should be called before any other device_*() function is used.
457 */
458 void device_init(void)
459 {
460 device_entries = NULL;
461 device_entries_sorted = 0;
462 n_device_entries = 0;
463
464 autodev_init();
465 }
466

  ViewVC Help
Powered by ViewVC 1.1.26