/[gxemul]/upstream/0.4.1/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

Annotation of /upstream/0.4.1/src/device.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 29 - (hide annotations)
Mon Oct 8 16:20:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 11407 byte(s)
0.4.1
1 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 dpavlin 24 * $Id: device.c,v 1.26 2006/04/06 19:17:37 debug Exp $
29 dpavlin 2 *
30     * Device registry framework.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36    
37     #include "device.h"
38 dpavlin 20 #include "memory.h"
39 dpavlin 2 #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 dpavlin 20 static struct pci_entry *pci_entries = NULL;
48     static int n_pci_entries = 0;
49 dpavlin 2
50 dpavlin 20
51 dpavlin 2 /*
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 dpavlin 20 * 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 dpavlin 22 void (*pci_lookup_initf(const char *name))(struct machine *machine,
146 dpavlin 20 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 dpavlin 2 * 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 dpavlin 20 int hi, lo;
174 dpavlin 2
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 dpavlin 20 lo = 0; hi = n_device_entries - 1;
187 dpavlin 2
188 dpavlin 20 while (lo <= hi) {
189     int r, i = (lo + hi) / 2;
190 dpavlin 2
191 dpavlin 20 /* printf("device_lookup(): i=%i (lo=%i hi=%i)\n", i, lo, hi);
192 dpavlin 2 printf(" name='%s', '%s'\n", name,
193     device_entries[i].name); */
194    
195     r = strcmp(name, device_entries[i].name);
196 dpavlin 20 if (r == 0) {
197 dpavlin 2 /* Found it! */
198     return &device_entries[i];
199     }
200    
201 dpavlin 20 /* Try left or right half: */
202     if (r < 0)
203     hi = i - 1;
204     if (r > 0)
205     lo = i + 1;
206     }
207 dpavlin 2
208 dpavlin 20 return NULL;
209 dpavlin 2 }
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 dpavlin 12 ssize_t i;
222 dpavlin 2 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 dpavlin 10 * Add a device to a machine. For example: "kn210 addr=0x12340000" adds a
257     * device called "kn210" at a specific address.
258 dpavlin 2 *
259 dpavlin 10 * TODO: This function is quite ugly, and should be cleaned up.
260 dpavlin 24 * name_and_params should be const.
261 dpavlin 2 */
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 dpavlin 22 int quoted;
269 dpavlin 2
270     memset(&devinit, 0, sizeof(struct devinit));
271     devinit.machine = machine;
272    
273     /* Default values: */
274     devinit.addr_mult = 1;
275 dpavlin 12 devinit.in_use = 1;
276 dpavlin 2
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 dpavlin 22 devinit.dma_irq_nr = -1;
291 dpavlin 2
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 dpavlin 20 } else if (strncmp(s2, "addr2=", 6) == 0) {
329     devinit.addr2 = mystrtoull(s3, NULL, 0);
330 dpavlin 2 } 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 dpavlin 20 } 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 dpavlin 2 } else if (strncmp(s2, "irq=", 4) == 0) {
345     devinit.irq_nr = mystrtoull(s3, NULL, 0);
346 dpavlin 22 } else if (strncmp(s2, "dma_irq=", 8) == 0) {
347     devinit.dma_irq_nr = mystrtoull(s3, NULL, 0);
348 dpavlin 12 } 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 dpavlin 22 quoted = 0;
354     while (*h) {
355     if (*h == '\'')
356     quoted = !quoted;
357 dpavlin 12 h++, len++;
358 dpavlin 22 if (!quoted && *h == ' ')
359     break;
360     }
361 dpavlin 12 devinit.name2 = malloc(len + 1);
362     if (devinit.name2 == NULL) {
363     fprintf(stderr, "out of memory\n");
364     exit(1);
365     }
366 dpavlin 22 h = s2 + 6;
367     if (*h == '\'')
368     len -= 2, h++;
369     snprintf(devinit.name2, len + 1, h);
370 dpavlin 2 } 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 dpavlin 22 quoted = 0;
381     while (*s2 != '\0' && (*s2 != ' ' || quoted) &&
382     *s2 != ',' && *s2 != ';') {
383     if (*s2 == '\'')
384     quoted = !quoted;
385 dpavlin 2 s2 ++;
386 dpavlin 22 }
387 dpavlin 2 }
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 dpavlin 10 *
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 dpavlin 2 */
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 dpavlin 10 * add all normal devices (from the src/devices/ directory).
455 dpavlin 2 *
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