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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 11370 byte(s)
0.3.8
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 22 * $Id: device.c,v 1.25 2006/02/18 21:03:11 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 2 */
261     void *device_add(struct machine *machine, char *name_and_params)
262     {
263     struct device_entry *p;
264     struct devinit devinit;
265     char *s2, *s3;
266     size_t len;
267 dpavlin 22 int quoted;
268 dpavlin 2
269     memset(&devinit, 0, sizeof(struct devinit));
270     devinit.machine = machine;
271    
272     /* Default values: */
273     devinit.addr_mult = 1;
274 dpavlin 12 devinit.in_use = 1;
275 dpavlin 2
276     /* Get the device name first: */
277     s2 = name_and_params;
278     while (s2[0] != ',' && s2[0] != ' ' && s2[0] != '\0')
279     s2 ++;
280    
281     len = (size_t)s2 - (size_t)name_and_params;
282     devinit.name = malloc(len + 1);
283     if (devinit.name == NULL) {
284     fprintf(stderr, "device_add(): out of memory\n");
285     exit(1);
286     }
287     memcpy(devinit.name, name_and_params, len);
288     devinit.name[len] = '\0';
289 dpavlin 22 devinit.dma_irq_nr = -1;
290 dpavlin 2
291     p = device_lookup(devinit.name);
292     if (p == NULL) {
293     fatal("no such device (\"%s\")\n", devinit.name);
294     if (device_exit_on_error)
295     exit(1);
296     else
297     goto return_fail;
298     }
299    
300     /* Get params from name_and_params: */
301     while (*s2 != '\0') {
302     /* Skip spaces, commas, and semicolons: */
303     while (*s2 == ' ' || *s2 == ',' || *s2 == ';')
304     s2 ++;
305    
306     if (*s2 == '\0')
307     break;
308    
309     /* s2 now points to the next param. eg "addr=1234" */
310    
311     /* Get a word (until there is a '=' sign): */
312     s3 = s2;
313     while (*s3 != '=' && *s3 != '\0')
314     s3 ++;
315     if (s3 == s2) {
316     fatal("weird param: %s\n", s2);
317     if (device_exit_on_error)
318     exit(1);
319     else
320     goto return_fail;
321     }
322     s3 ++;
323     /* s3 now points to the parameter value ("1234") */
324    
325     if (strncmp(s2, "addr=", 5) == 0) {
326     devinit.addr = mystrtoull(s3, NULL, 0);
327 dpavlin 20 } else if (strncmp(s2, "addr2=", 6) == 0) {
328     devinit.addr2 = mystrtoull(s3, NULL, 0);
329 dpavlin 2 } else if (strncmp(s2, "len=", 4) == 0) {
330     devinit.len = mystrtoull(s3, NULL, 0);
331     } else if (strncmp(s2, "addr_mult=", 10) == 0) {
332     devinit.addr_mult = mystrtoull(s3, NULL, 0);
333 dpavlin 20 } else if (strncmp(s2, "pci_little_endian=", 18) == 0) {
334     devinit.pci_little_endian = mystrtoull(s3, NULL, 0);
335     switch (devinit.pci_little_endian) {
336     case 0: break;
337     case 1: devinit.pci_little_endian =
338     MEM_PCI_LITTLE_ENDIAN;
339     break;
340     default:fatal("Bad pci_little_endian value.\n");
341     exit(1);
342     }
343 dpavlin 2 } else if (strncmp(s2, "irq=", 4) == 0) {
344     devinit.irq_nr = mystrtoull(s3, NULL, 0);
345 dpavlin 22 } else if (strncmp(s2, "dma_irq=", 8) == 0) {
346     devinit.dma_irq_nr = mystrtoull(s3, NULL, 0);
347 dpavlin 12 } else if (strncmp(s2, "in_use=", 7) == 0) {
348     devinit.in_use = mystrtoull(s3, NULL, 0);
349     } else if (strncmp(s2, "name2=", 6) == 0) {
350     char *h = s2 + 6;
351     size_t len = 0;
352 dpavlin 22 quoted = 0;
353     while (*h) {
354     if (*h == '\'')
355     quoted = !quoted;
356 dpavlin 12 h++, len++;
357 dpavlin 22 if (!quoted && *h == ' ')
358     break;
359     }
360 dpavlin 12 devinit.name2 = malloc(len + 1);
361     if (devinit.name2 == NULL) {
362     fprintf(stderr, "out of memory\n");
363     exit(1);
364     }
365 dpavlin 22 h = s2 + 6;
366     if (*h == '\'')
367     len -= 2, h++;
368     snprintf(devinit.name2, len + 1, h);
369 dpavlin 2 } else {
370     fatal("unknown param: %s\n", s2);
371     if (device_exit_on_error)
372     exit(1);
373     else
374     goto return_fail;
375     }
376    
377     /* skip to the next param: */
378     s2 = s3;
379 dpavlin 22 quoted = 0;
380     while (*s2 != '\0' && (*s2 != ' ' || quoted) &&
381     *s2 != ',' && *s2 != ';') {
382     if (*s2 == '\'')
383     quoted = !quoted;
384 dpavlin 2 s2 ++;
385 dpavlin 22 }
386 dpavlin 2 }
387    
388    
389     /*
390     * Call the init function for this device:
391     */
392    
393     devinit.return_ptr = NULL;
394    
395     if (!p->initf(&devinit)) {
396     fatal("error adding device (\"%s\")\n", name_and_params);
397     if (device_exit_on_error)
398     exit(1);
399     else
400     goto return_fail;
401     }
402    
403     free(devinit.name);
404     return devinit.return_ptr;
405    
406     return_fail:
407     free(devinit.name);
408     return NULL;
409     }
410    
411    
412     /*
413     * device_dumplist():
414     *
415     * Dump a list of all registered devices. (If the list is not sorted when
416     * this function is called, it is implicitly sorted.)
417     */
418     void device_dumplist(void)
419     {
420     int i;
421    
422     if (!device_entries_sorted)
423     sort_entries();
424    
425     for (i=0; i<n_device_entries; i++) {
426     debug(" %s", device_entries[i].name);
427    
428     /* TODO: flags? */
429    
430     debug("\n");
431     }
432     }
433    
434    
435     /*
436     * device_set_exit_on_error():
437 dpavlin 10 *
438     * This function selects the behaviour of the emulator when a device is not
439     * found. During startup, it is nicest to abort the whole emulator session,
440     * but if a device addition is attempted from within the debugger, then it is
441     * nicer to just print a warning and continue.
442 dpavlin 2 */
443     void device_set_exit_on_error(int exit_on_error)
444     {
445     device_exit_on_error = exit_on_error;
446     }
447    
448    
449     /*
450     * device_init():
451     *
452     * Initialize the device registry, and call autodev_init() to automatically
453 dpavlin 10 * add all normal devices (from the src/devices/ directory).
454 dpavlin 2 *
455     * This function should be called before any other device_*() function is used.
456     */
457     void device_init(void)
458     {
459     device_entries = NULL;
460     device_entries_sorted = 0;
461     n_device_entries = 0;
462    
463     autodev_init();
464     }
465    

  ViewVC Help
Powered by ViewVC 1.1.26