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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 13 - (hide annotations)
Mon Oct 8 16:18:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 9511 byte(s)
0.3.5
1 dpavlin 2 /*
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 dpavlin 12 * $Id: device.c,v 1.16 2005/08/10 22:25:50 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     #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 dpavlin 10 if (step & 1)
168     step = (step/2) + 1;
169     else
170     step /= 2;
171 dpavlin 2 }
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 dpavlin 12 ssize_t i;
185 dpavlin 2 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 dpavlin 10 * Add a device to a machine. For example: "kn210 addr=0x12340000" adds a
220     * device called "kn210" at a specific address.
221 dpavlin 2 *
222 dpavlin 10 * TODO: This function is quite ugly, and should be cleaned up.
223 dpavlin 2 */
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 dpavlin 12 devinit.in_use = 1;
237 dpavlin 2
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 dpavlin 12 } 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 dpavlin 2 } 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 dpavlin 10 *
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 dpavlin 2 */
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 dpavlin 10 * add all normal devices (from the src/devices/ directory).
387 dpavlin 2 *
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