Deleted Added
full compact
eisaconf.c (31016) eisaconf.c (33181)
1/*
2 * EISA bus probe and attach routines
3 *
4 * Copyright (c) 1995, 1996 Justin T. Gibbs.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice immediately at the beginning of the file, without modification,
12 * this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
1/*
2 * EISA bus probe and attach routines
3 *
4 * Copyright (c) 1995, 1996 Justin T. Gibbs.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice immediately at the beginning of the file, without modification,
12 * this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $Id: eisaconf.c,v 1.32 1997/10/28 15:58:08 bde Exp $
31 * $Id: eisaconf.c,v 1.33 1997/11/07 08:52:24 phk Exp $
32 */
33
34#include "opt_eisa.h"
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/malloc.h>
40
41#include <machine/limits.h>
42
43#include <i386/eisa/eisaconf.h>
44
45#include <sys/interrupt.h>
46
47struct eisa_device_node{
48 struct eisa_device dev;
49 struct eisa_device_node *next;
50};
51
52/*
53 * This should probably be a list of "struct device" once it exists.
54 * A struct device will incorperate ioconf and driver entry point data
55 * regardless of how its attached to the system (via unions) as well
56 * as more generic information that all device types should support (unit
57 * number, if its installed, etc).
58 */
59static struct eisa_device_node *eisa_dev_list;
60static struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list;
61static u_long eisa_unit;
62
63static struct eisa_driver mainboard_drv = {
64 "eisa",
65 NULL,
66 NULL,
67 NULL,
68 &eisa_unit
69 };
70
71/*
72 * Add the mainboard_drv to the eisa driver linkerset so that it is
73 * defined even if no EISA drivers are linked into the kernel.
74 */
75DATA_SET (eisadriver_set, mainboard_drv);
76
77/*
78 * Local function declarations and static variables
79 */
32 */
33
34#include "opt_eisa.h"
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/malloc.h>
40
41#include <machine/limits.h>
42
43#include <i386/eisa/eisaconf.h>
44
45#include <sys/interrupt.h>
46
47struct eisa_device_node{
48 struct eisa_device dev;
49 struct eisa_device_node *next;
50};
51
52/*
53 * This should probably be a list of "struct device" once it exists.
54 * A struct device will incorperate ioconf and driver entry point data
55 * regardless of how its attached to the system (via unions) as well
56 * as more generic information that all device types should support (unit
57 * number, if its installed, etc).
58 */
59static struct eisa_device_node *eisa_dev_list;
60static struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list;
61static u_long eisa_unit;
62
63static struct eisa_driver mainboard_drv = {
64 "eisa",
65 NULL,
66 NULL,
67 NULL,
68 &eisa_unit
69 };
70
71/*
72 * Add the mainboard_drv to the eisa driver linkerset so that it is
73 * defined even if no EISA drivers are linked into the kernel.
74 */
75DATA_SET (eisadriver_set, mainboard_drv);
76
77/*
78 * Local function declarations and static variables
79 */
80void eisa_reg_print __P((struct eisa_device *e_dev, char *string,
81 char *separator));
80static void eisa_reg_print __P((struct eisa_device *e_dev,
81 char *string, char *separator));
82static int eisa_add_resvaddr __P((struct eisa_device *e_dev,
83 struct resvlist *head, u_long base,
84 u_long size, int flags));
85static int eisa_reg_resvaddr __P((struct eisa_device *e_dev,
86 struct resvlist *head, resvaddr_t *resvaddr,
87 int *reg_count));
88
89/*
90 * Keep some state about what we've printed so far
91 * to make probe output pretty.
92 */
93static struct {
94 int in_registration;/* reg_start has been called */
95 int num_interrupts;
96 int num_ioaddrs;
97 int num_maddrs;
98 int column; /* How much we have output so far. */
99#define MAX_COL 80
100} reg_state;
101
102/* Global variable, so UserConfig can change it. */
103#ifndef EISA_SLOTS
104#define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */
105#endif
106int num_eisa_slots = EISA_SLOTS;
107
108/*
109** probe for EISA devices
110*/
111void
112eisa_configure()
113{
114 int i,slot;
115 struct eisa_device_node *dev_node;
116 struct eisa_driver **e_drvp;
117 struct eisa_driver *e_drv;
118 struct eisa_device *e_dev;
119 int eisaBase = 0xc80;
120 eisa_id_t eisa_id;
121
122 e_drvp = (struct eisa_driver**)eisadriver_set.ls_items;
123
124 for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) {
125 int id_size = sizeof(eisa_id);
126 eisa_id = 0;
127 for( i = 0; i < id_size; i++ ) {
128 outb(eisaBase,0x80 + i); /*Some cards require priming*/
129 eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT);
130 }
131 if (eisa_id & 0x80000000)
132 continue; /* no EISA card in slot */
133
134 /* Prepare an eisa_device_node for this slot */
135 dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node),
136 M_DEVBUF, M_NOWAIT);
137 if (!dev_node) {
138 printf("eisa0: cannot malloc eisa_device_node");
139 break; /* Try to attach what we have already */
140 }
141 bzero(dev_node, sizeof(*dev_node));
142 e_dev = &(dev_node->dev);
143
144 e_dev->id = eisa_id;
145
146 e_dev->full_name = "Unattached Device";
147
148 e_dev->ioconf.slot = slot;
149
150 /* Initialize our lists of reserved addresses */
151 LIST_INIT(&(e_dev->ioconf.ioaddrs));
152 LIST_INIT(&(e_dev->ioconf.maddrs));
153 TAILQ_INIT(&(e_dev->ioconf.irqs));
154
155 *eisa_dev_list_tail = dev_node;
156 eisa_dev_list_tail = &dev_node->next;
157 }
158
159 dev_node = eisa_dev_list;
160
161 /*
162 * "Attach" the system board
163 */
164
165 /* The first will be the motherboard in a true EISA system */
166 if (dev_node && (dev_node->dev.ioconf.slot == 0)) {
167 char *idstring;
168
169 e_dev = &dev_node->dev;
170 e_dev->driver = &mainboard_drv;
171 e_dev->unit = (*e_dev->driver->unit)++;
172 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
173 M_DEVBUF, M_NOWAIT);
174 if (idstring == NULL) {
175 panic("Eisa probe unable to malloc");
176 }
177 sprintf(idstring, "%c%c%c%x%x (System Board)",
178 EISA_MFCTR_CHAR0(e_dev->id),
179 EISA_MFCTR_CHAR1(e_dev->id),
180 EISA_MFCTR_CHAR2(e_dev->id),
181 EISA_PRODUCT_ID(e_dev->id),
182 EISA_REVISION_ID(e_dev->id));
183 e_dev->full_name = idstring;
184
185 printf("%s%ld: <%s>\n",
186 e_dev->driver->name,
187 e_dev->unit,
188 e_dev->full_name);
189
190 /* Should set the iosize, but I don't have a spec handy */
191 printf("Probing for devices on the EISA bus\n");
192 dev_node = dev_node->next;
193 }
194
195 if (!eisa_dev_list) {
196 /*
197 * No devices.
198 */
199 return;
200 }
201 /*
202 * See what devices we recognize.
203 */
204 while((e_drv = *e_drvp++)) {
205 if (e_drv->probe)
206 (*e_drv->probe)();
207 }
208
209 /*
210 * Attach the devices we found in slot order
211 */
212 for (; dev_node; dev_node=dev_node->next) {
213 e_dev = &dev_node->dev;
214 e_drv = e_dev->driver;
215
216 if (e_drv) {
217 /*
218 * Determine the proper unit number for this device.
219 * Here we should look in the device table generated
220 * by config to see if this type of device is enabled
221 * either generically or for this particular address
222 * as well as determine if a reserved unit number
223 * should be used. We should also ensure that the
224 * "next availible unit number" skips over "wired" unit
225 * numbers. This will be done after config is fixed or
226 * some other configuration method is chosen.
227 */
228 e_dev->unit = (*e_drv->unit)++;
229 if ((*e_drv->attach)(e_dev) < 0) {
230 /* Ensure registration has ended */
231 reg_state.in_registration = 0;
232 printf("\n%s0:%d <%s> attach failed\n",
233 mainboard_drv.name,
234 e_dev->ioconf.slot,
235 e_dev->full_name);
236 continue;
237 }
238 /* Ensure registration has ended */
239 reg_state.in_registration = 0;
240 }
241 else {
242 /* Announce unattached device */
243 printf("%s0:%d <%c%c%c%x%x=0x%x> unknown device\n",
244 mainboard_drv.name,
245 e_dev->ioconf.slot,
246 EISA_MFCTR_CHAR0(e_dev->id),
247 EISA_MFCTR_CHAR1(e_dev->id),
248 EISA_MFCTR_CHAR2(e_dev->id),
249 EISA_PRODUCT_ID(e_dev->id),
250 EISA_REVISION_ID(e_dev->id),
251 e_dev->id);
252 }
253 }
254}
255
256struct eisa_device *
257eisa_match_dev(e_dev, match_func)
258 struct eisa_device *e_dev;
259 const char* (*match_func)(eisa_id_t);
260{
261 struct eisa_device_node *e_node = eisa_dev_list;
262
263 if (e_dev) {
264 /* Start our search from the last successful match */
265 e_node = ((struct eisa_device_node *)e_dev)->next;
266 }
267
268 for(; e_node; e_node = e_node->next) {
269 const char *result;
270 if (e_node->dev.driver) {
271 /* Already claimed */
272 continue;
273 }
274 result = (*match_func)(e_node->dev.id);
275 if (result) {
276 e_node->dev.full_name = result;
277 return (&(e_node->dev));
278 }
279 }
280 return NULL;
281}
282
283/* Interrupt and I/O space registration facitlities */
284void
285eisa_reg_start(e_dev)
286 struct eisa_device *e_dev;
287{
288 /*
289 * Announce the device.
290 */
291 char *string;
292
293 reg_state.in_registration = 1;
294 reg_state.num_interrupts = 0;
295 reg_state.num_ioaddrs = 0;
296 reg_state.num_maddrs = 0;
297 reg_state.column = 0;
298
299 string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1,
300 M_TEMP, M_NOWAIT);
301 if(!string) {
302 printf("eisa0: cannot malloc device description string\n");
303 return;
304 }
305 sprintf(string, " <%s>", e_dev->full_name);
306 eisa_reg_print(e_dev, string, /*separator=*/NULL);
307 free(string, M_TEMP);
308}
309
310/*
311 * Output registration information mindfull of screen wrap.
312 * Output an optional character separator before the string
313 * if the line does not wrap.
314 */
82static int eisa_add_resvaddr __P((struct eisa_device *e_dev,
83 struct resvlist *head, u_long base,
84 u_long size, int flags));
85static int eisa_reg_resvaddr __P((struct eisa_device *e_dev,
86 struct resvlist *head, resvaddr_t *resvaddr,
87 int *reg_count));
88
89/*
90 * Keep some state about what we've printed so far
91 * to make probe output pretty.
92 */
93static struct {
94 int in_registration;/* reg_start has been called */
95 int num_interrupts;
96 int num_ioaddrs;
97 int num_maddrs;
98 int column; /* How much we have output so far. */
99#define MAX_COL 80
100} reg_state;
101
102/* Global variable, so UserConfig can change it. */
103#ifndef EISA_SLOTS
104#define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */
105#endif
106int num_eisa_slots = EISA_SLOTS;
107
108/*
109** probe for EISA devices
110*/
111void
112eisa_configure()
113{
114 int i,slot;
115 struct eisa_device_node *dev_node;
116 struct eisa_driver **e_drvp;
117 struct eisa_driver *e_drv;
118 struct eisa_device *e_dev;
119 int eisaBase = 0xc80;
120 eisa_id_t eisa_id;
121
122 e_drvp = (struct eisa_driver**)eisadriver_set.ls_items;
123
124 for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) {
125 int id_size = sizeof(eisa_id);
126 eisa_id = 0;
127 for( i = 0; i < id_size; i++ ) {
128 outb(eisaBase,0x80 + i); /*Some cards require priming*/
129 eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT);
130 }
131 if (eisa_id & 0x80000000)
132 continue; /* no EISA card in slot */
133
134 /* Prepare an eisa_device_node for this slot */
135 dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node),
136 M_DEVBUF, M_NOWAIT);
137 if (!dev_node) {
138 printf("eisa0: cannot malloc eisa_device_node");
139 break; /* Try to attach what we have already */
140 }
141 bzero(dev_node, sizeof(*dev_node));
142 e_dev = &(dev_node->dev);
143
144 e_dev->id = eisa_id;
145
146 e_dev->full_name = "Unattached Device";
147
148 e_dev->ioconf.slot = slot;
149
150 /* Initialize our lists of reserved addresses */
151 LIST_INIT(&(e_dev->ioconf.ioaddrs));
152 LIST_INIT(&(e_dev->ioconf.maddrs));
153 TAILQ_INIT(&(e_dev->ioconf.irqs));
154
155 *eisa_dev_list_tail = dev_node;
156 eisa_dev_list_tail = &dev_node->next;
157 }
158
159 dev_node = eisa_dev_list;
160
161 /*
162 * "Attach" the system board
163 */
164
165 /* The first will be the motherboard in a true EISA system */
166 if (dev_node && (dev_node->dev.ioconf.slot == 0)) {
167 char *idstring;
168
169 e_dev = &dev_node->dev;
170 e_dev->driver = &mainboard_drv;
171 e_dev->unit = (*e_dev->driver->unit)++;
172 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
173 M_DEVBUF, M_NOWAIT);
174 if (idstring == NULL) {
175 panic("Eisa probe unable to malloc");
176 }
177 sprintf(idstring, "%c%c%c%x%x (System Board)",
178 EISA_MFCTR_CHAR0(e_dev->id),
179 EISA_MFCTR_CHAR1(e_dev->id),
180 EISA_MFCTR_CHAR2(e_dev->id),
181 EISA_PRODUCT_ID(e_dev->id),
182 EISA_REVISION_ID(e_dev->id));
183 e_dev->full_name = idstring;
184
185 printf("%s%ld: <%s>\n",
186 e_dev->driver->name,
187 e_dev->unit,
188 e_dev->full_name);
189
190 /* Should set the iosize, but I don't have a spec handy */
191 printf("Probing for devices on the EISA bus\n");
192 dev_node = dev_node->next;
193 }
194
195 if (!eisa_dev_list) {
196 /*
197 * No devices.
198 */
199 return;
200 }
201 /*
202 * See what devices we recognize.
203 */
204 while((e_drv = *e_drvp++)) {
205 if (e_drv->probe)
206 (*e_drv->probe)();
207 }
208
209 /*
210 * Attach the devices we found in slot order
211 */
212 for (; dev_node; dev_node=dev_node->next) {
213 e_dev = &dev_node->dev;
214 e_drv = e_dev->driver;
215
216 if (e_drv) {
217 /*
218 * Determine the proper unit number for this device.
219 * Here we should look in the device table generated
220 * by config to see if this type of device is enabled
221 * either generically or for this particular address
222 * as well as determine if a reserved unit number
223 * should be used. We should also ensure that the
224 * "next availible unit number" skips over "wired" unit
225 * numbers. This will be done after config is fixed or
226 * some other configuration method is chosen.
227 */
228 e_dev->unit = (*e_drv->unit)++;
229 if ((*e_drv->attach)(e_dev) < 0) {
230 /* Ensure registration has ended */
231 reg_state.in_registration = 0;
232 printf("\n%s0:%d <%s> attach failed\n",
233 mainboard_drv.name,
234 e_dev->ioconf.slot,
235 e_dev->full_name);
236 continue;
237 }
238 /* Ensure registration has ended */
239 reg_state.in_registration = 0;
240 }
241 else {
242 /* Announce unattached device */
243 printf("%s0:%d <%c%c%c%x%x=0x%x> unknown device\n",
244 mainboard_drv.name,
245 e_dev->ioconf.slot,
246 EISA_MFCTR_CHAR0(e_dev->id),
247 EISA_MFCTR_CHAR1(e_dev->id),
248 EISA_MFCTR_CHAR2(e_dev->id),
249 EISA_PRODUCT_ID(e_dev->id),
250 EISA_REVISION_ID(e_dev->id),
251 e_dev->id);
252 }
253 }
254}
255
256struct eisa_device *
257eisa_match_dev(e_dev, match_func)
258 struct eisa_device *e_dev;
259 const char* (*match_func)(eisa_id_t);
260{
261 struct eisa_device_node *e_node = eisa_dev_list;
262
263 if (e_dev) {
264 /* Start our search from the last successful match */
265 e_node = ((struct eisa_device_node *)e_dev)->next;
266 }
267
268 for(; e_node; e_node = e_node->next) {
269 const char *result;
270 if (e_node->dev.driver) {
271 /* Already claimed */
272 continue;
273 }
274 result = (*match_func)(e_node->dev.id);
275 if (result) {
276 e_node->dev.full_name = result;
277 return (&(e_node->dev));
278 }
279 }
280 return NULL;
281}
282
283/* Interrupt and I/O space registration facitlities */
284void
285eisa_reg_start(e_dev)
286 struct eisa_device *e_dev;
287{
288 /*
289 * Announce the device.
290 */
291 char *string;
292
293 reg_state.in_registration = 1;
294 reg_state.num_interrupts = 0;
295 reg_state.num_ioaddrs = 0;
296 reg_state.num_maddrs = 0;
297 reg_state.column = 0;
298
299 string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1,
300 M_TEMP, M_NOWAIT);
301 if(!string) {
302 printf("eisa0: cannot malloc device description string\n");
303 return;
304 }
305 sprintf(string, " <%s>", e_dev->full_name);
306 eisa_reg_print(e_dev, string, /*separator=*/NULL);
307 free(string, M_TEMP);
308}
309
310/*
311 * Output registration information mindfull of screen wrap.
312 * Output an optional character separator before the string
313 * if the line does not wrap.
314 */
315void
315static void
316eisa_reg_print(e_dev, string, separator)
317 struct eisa_device *e_dev;
318 char *string;
319 char *separator;
320{
321 int len = strlen(string);
322
323 if(separator)
324 len++;
325
326 if(reg_state.column + len > MAX_COL) {
327 printf("\n");
328 reg_state.column = 0;
329 }
330 else if(separator) {
331 printf("%c", *separator);
332 reg_state.column++;
333 }
334
335 if(reg_state.column == 0)
336 reg_state.column += printf("%s%ld:%s",
337 e_dev->driver->name,
338 e_dev->unit,
339 string);
340 else
341 reg_state.column += printf("%s", string);
342}
343
344/* Interrupt and I/O space registration facitlities */
345void
346eisa_reg_end(e_dev)
347 struct eisa_device *e_dev;
348{
349 if( reg_state.in_registration )
350 {
351 char string[25];
352
353 sprintf(string, " on %s0 slot %d",
354 mainboard_drv.name,
355 e_dev->ioconf.slot);
356 eisa_reg_print(e_dev, string, NULL);
357 printf("\n");
358 reg_state.in_registration = 0;
359 }
360 else
361 printf("eisa_reg_end called outside of a "
362 "registration session\n");
363}
364
365int
366eisa_add_intr(e_dev, irq)
367 struct eisa_device *e_dev;
368 int irq;
369{
370 struct irq_node *irq_info;
371
372 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
373 M_NOWAIT);
374 if (irq_info == NULL)
375 return (1);
376
377 irq_info->irq_no = irq;
378 irq_info->idesc = NULL;
379 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
380 return 0;
381}
382
383int
384eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared)
385 struct eisa_device *e_dev;
386 int irq;
387 void (*func)(void *);
388 void *arg;
389 u_int *maskptr;
390 int shared;
391{
392 char string[25];
393 char separator = ',';
394
395#if NOT_YET
396 /*
397 * Punt on conflict detection for the moment.
398 * I want to develop a generic routine to do
399 * this for all device types.
400 */
401 int checkthese = CC_IRQ;
402 if (haveseen_dev(dev, checkthese))
403 return 1;
404#endif
405 if (reg_state.in_registration) {
406 /*
407 * Find the first instance of this irq that has a
408 * NULL idesc.
409 */
410 struct irq_node *cur_irq;
411
412 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
413 while (cur_irq != NULL) {
414 if (cur_irq->irq_no == irq
415 && cur_irq->idesc == NULL) {
416 /* XXX use cfg->devdata */
417 void *dev_instance = (void *)-1;
418
419 cur_irq->idesc = intr_create(dev_instance,
420 irq,
421 func,
422 arg,
423 maskptr, 0);
424 break;
425 }
426 cur_irq = TAILQ_NEXT(cur_irq, links);
427 }
428
429 if (cur_irq == NULL || cur_irq->idesc == NULL)
430 return (-1);
431 } else {
432 return EPERM;
433 }
434
435 sprintf(string, " irq %d", irq);
436 eisa_reg_print(e_dev, string, reg_state.num_interrupts ?
437 &separator : NULL);
438 reg_state.num_interrupts++;
439 return (0);
440}
441
442int
443eisa_release_intr(e_dev, irq, func)
444 struct eisa_device *e_dev;
445 int irq;
446 void (*func)(void *);
447{
448 int result;
449 struct irq_node *cur_irq;
450
451 result = -1;
452 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
453 while (cur_irq != NULL) {
454 if (cur_irq->irq_no == irq) {
455 if (cur_irq->idesc != NULL)
456 intr_destroy(cur_irq->idesc);
457 cur_irq = TAILQ_NEXT(cur_irq, links);
458 TAILQ_REMOVE(&e_dev->ioconf.irqs, cur_irq, links);
459 result = 0;
460 } else {
461 cur_irq = TAILQ_NEXT(cur_irq, links);
462 }
463 }
464 if (result != 0) {
465 printf("%s%ld: Attempted to release an interrupt (%d) "
466 "it doesn't own\n", e_dev->driver->name,
467 e_dev->unit, irq);
468 }
469
470 return (result);
471}
472
473int
474eisa_enable_intr(e_dev, irq)
475 struct eisa_device *e_dev;
476 int irq;
477{
478 struct irq_node *cur_irq;
479 int result;
480
481 result = -1;
482 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
483 while (cur_irq != NULL) {
484 if (cur_irq->irq_no == irq
485 && cur_irq->idesc != NULL) {
486 result = intr_connect(cur_irq->idesc);
487 }
488 cur_irq = TAILQ_NEXT(cur_irq, links);
489 }
490 return (result);
491}
492
493static int
494eisa_add_resvaddr(e_dev, head, base, size, flags)
495 struct eisa_device *e_dev;
496 struct resvlist *head;
497 u_long base;
498 u_long size;
499 int flags;
500{
501 resvaddr_t *reservation;
502
503 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
504 M_DEVBUF, M_NOWAIT);
505 if(!reservation)
506 return (ENOMEM);
507
508 reservation->addr = base;
509 reservation->size = size;
510 reservation->flags = flags;
511
512 if (!head->lh_first) {
513 LIST_INSERT_HEAD(head, reservation, links);
514 }
515 else {
516 resvaddr_t *node;
517 for(node = head->lh_first; node; node = node->links.le_next) {
518 if (node->addr > reservation->addr) {
519 /*
520 * List is sorted in increasing
521 * address order.
522 */
523 LIST_INSERT_BEFORE(node, reservation, links);
524 break;
525 }
526
527 if (node->addr == reservation->addr) {
528 /*
529 * If the entry we want to add
530 * matches any already in here,
531 * fail.
532 */
533 free(reservation, M_DEVBUF);
534 return (EEXIST);
535 }
536
537 if (!node->links.le_next) {
538 LIST_INSERT_AFTER(node, reservation, links);
539 break;
540 }
541 }
542 }
543 return (0);
544}
545
546int
547eisa_add_mspace(e_dev, mbase, msize, flags)
548 struct eisa_device *e_dev;
549 u_long mbase;
550 u_long msize;
551 int flags;
552{
553 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
554 flags);
555}
556
557int
558eisa_add_iospace(e_dev, iobase, iosize, flags)
559 struct eisa_device *e_dev;
560 u_long iobase;
561 u_long iosize;
562 int flags;
563{
564 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
565 iosize, flags);
566}
567
568static int
569eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count)
570 struct eisa_device *e_dev;
571 struct resvlist *head;
572 resvaddr_t *resvaddr;
573 int *reg_count;
574{
575 if (reg_state.in_registration) {
576 resvaddr_t *node;
577 /*
578 * Ensure that this resvaddr is actually in the devices'
579 * reservation list.
580 */
581 for(node = head->lh_first; node;
582 node = node->links.le_next) {
583 if (node == resvaddr) {
584 char buf[35];
585 char separator = ',';
586 char *string = buf;
587
588 if (*reg_count == 0) {
589 /* First time */
590 string += sprintf(string, " at");
591 }
592
593 if (node->size == 1
594 || (node->flags & RESVADDR_BITMASK))
595 sprintf(string, " 0x%lx", node->addr);
596 else
597 sprintf(string, " 0x%lx-0x%lx",
598 node->addr,
599 node->addr + node->size - 1);
600 eisa_reg_print(e_dev, buf,
601 *reg_count ? &separator : NULL);
602 (*reg_count)++;
603 return (0);
604 }
605 }
606 return (ENOENT);
607 }
608 return EPERM;
609}
610
611int
612eisa_reg_mspace(e_dev, resvaddr)
613 struct eisa_device *e_dev;
614 resvaddr_t *resvaddr;
615{
616#ifdef NOT_YET
617 /*
618 * Punt on conflict detection for the moment.
619 * I want to develop a generic routine to do
620 * this for all device types.
621 */
622 int checkthese = CC_MADDR;
623 if (haveseen_dev(dev, checkthese))
624 return -1;
625#endif
626 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr,
627 &(reg_state.num_maddrs)));
628}
629
630int
631eisa_reg_iospace(e_dev, resvaddr)
632 struct eisa_device *e_dev;
633 resvaddr_t *resvaddr;
634{
635#ifdef NOT_YET
636 /*
637 * Punt on conflict detection for the moment.
638 * I want to develop a generic routine to do
639 * this for all device types.
640 */
641 int checkthese = CC_IOADDR;
642 if (haveseen_dev(dev, checkthese))
643 return -1;
644#endif
645 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr,
646 &(reg_state.num_ioaddrs)));
647}
648
649int
650eisa_registerdev(e_dev, driver)
651 struct eisa_device *e_dev;
652 struct eisa_driver *driver;
653{
654 e_dev->driver = driver; /* Driver now owns this device */
655 return (0);
656}
657
316eisa_reg_print(e_dev, string, separator)
317 struct eisa_device *e_dev;
318 char *string;
319 char *separator;
320{
321 int len = strlen(string);
322
323 if(separator)
324 len++;
325
326 if(reg_state.column + len > MAX_COL) {
327 printf("\n");
328 reg_state.column = 0;
329 }
330 else if(separator) {
331 printf("%c", *separator);
332 reg_state.column++;
333 }
334
335 if(reg_state.column == 0)
336 reg_state.column += printf("%s%ld:%s",
337 e_dev->driver->name,
338 e_dev->unit,
339 string);
340 else
341 reg_state.column += printf("%s", string);
342}
343
344/* Interrupt and I/O space registration facitlities */
345void
346eisa_reg_end(e_dev)
347 struct eisa_device *e_dev;
348{
349 if( reg_state.in_registration )
350 {
351 char string[25];
352
353 sprintf(string, " on %s0 slot %d",
354 mainboard_drv.name,
355 e_dev->ioconf.slot);
356 eisa_reg_print(e_dev, string, NULL);
357 printf("\n");
358 reg_state.in_registration = 0;
359 }
360 else
361 printf("eisa_reg_end called outside of a "
362 "registration session\n");
363}
364
365int
366eisa_add_intr(e_dev, irq)
367 struct eisa_device *e_dev;
368 int irq;
369{
370 struct irq_node *irq_info;
371
372 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
373 M_NOWAIT);
374 if (irq_info == NULL)
375 return (1);
376
377 irq_info->irq_no = irq;
378 irq_info->idesc = NULL;
379 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
380 return 0;
381}
382
383int
384eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared)
385 struct eisa_device *e_dev;
386 int irq;
387 void (*func)(void *);
388 void *arg;
389 u_int *maskptr;
390 int shared;
391{
392 char string[25];
393 char separator = ',';
394
395#if NOT_YET
396 /*
397 * Punt on conflict detection for the moment.
398 * I want to develop a generic routine to do
399 * this for all device types.
400 */
401 int checkthese = CC_IRQ;
402 if (haveseen_dev(dev, checkthese))
403 return 1;
404#endif
405 if (reg_state.in_registration) {
406 /*
407 * Find the first instance of this irq that has a
408 * NULL idesc.
409 */
410 struct irq_node *cur_irq;
411
412 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
413 while (cur_irq != NULL) {
414 if (cur_irq->irq_no == irq
415 && cur_irq->idesc == NULL) {
416 /* XXX use cfg->devdata */
417 void *dev_instance = (void *)-1;
418
419 cur_irq->idesc = intr_create(dev_instance,
420 irq,
421 func,
422 arg,
423 maskptr, 0);
424 break;
425 }
426 cur_irq = TAILQ_NEXT(cur_irq, links);
427 }
428
429 if (cur_irq == NULL || cur_irq->idesc == NULL)
430 return (-1);
431 } else {
432 return EPERM;
433 }
434
435 sprintf(string, " irq %d", irq);
436 eisa_reg_print(e_dev, string, reg_state.num_interrupts ?
437 &separator : NULL);
438 reg_state.num_interrupts++;
439 return (0);
440}
441
442int
443eisa_release_intr(e_dev, irq, func)
444 struct eisa_device *e_dev;
445 int irq;
446 void (*func)(void *);
447{
448 int result;
449 struct irq_node *cur_irq;
450
451 result = -1;
452 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
453 while (cur_irq != NULL) {
454 if (cur_irq->irq_no == irq) {
455 if (cur_irq->idesc != NULL)
456 intr_destroy(cur_irq->idesc);
457 cur_irq = TAILQ_NEXT(cur_irq, links);
458 TAILQ_REMOVE(&e_dev->ioconf.irqs, cur_irq, links);
459 result = 0;
460 } else {
461 cur_irq = TAILQ_NEXT(cur_irq, links);
462 }
463 }
464 if (result != 0) {
465 printf("%s%ld: Attempted to release an interrupt (%d) "
466 "it doesn't own\n", e_dev->driver->name,
467 e_dev->unit, irq);
468 }
469
470 return (result);
471}
472
473int
474eisa_enable_intr(e_dev, irq)
475 struct eisa_device *e_dev;
476 int irq;
477{
478 struct irq_node *cur_irq;
479 int result;
480
481 result = -1;
482 cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
483 while (cur_irq != NULL) {
484 if (cur_irq->irq_no == irq
485 && cur_irq->idesc != NULL) {
486 result = intr_connect(cur_irq->idesc);
487 }
488 cur_irq = TAILQ_NEXT(cur_irq, links);
489 }
490 return (result);
491}
492
493static int
494eisa_add_resvaddr(e_dev, head, base, size, flags)
495 struct eisa_device *e_dev;
496 struct resvlist *head;
497 u_long base;
498 u_long size;
499 int flags;
500{
501 resvaddr_t *reservation;
502
503 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
504 M_DEVBUF, M_NOWAIT);
505 if(!reservation)
506 return (ENOMEM);
507
508 reservation->addr = base;
509 reservation->size = size;
510 reservation->flags = flags;
511
512 if (!head->lh_first) {
513 LIST_INSERT_HEAD(head, reservation, links);
514 }
515 else {
516 resvaddr_t *node;
517 for(node = head->lh_first; node; node = node->links.le_next) {
518 if (node->addr > reservation->addr) {
519 /*
520 * List is sorted in increasing
521 * address order.
522 */
523 LIST_INSERT_BEFORE(node, reservation, links);
524 break;
525 }
526
527 if (node->addr == reservation->addr) {
528 /*
529 * If the entry we want to add
530 * matches any already in here,
531 * fail.
532 */
533 free(reservation, M_DEVBUF);
534 return (EEXIST);
535 }
536
537 if (!node->links.le_next) {
538 LIST_INSERT_AFTER(node, reservation, links);
539 break;
540 }
541 }
542 }
543 return (0);
544}
545
546int
547eisa_add_mspace(e_dev, mbase, msize, flags)
548 struct eisa_device *e_dev;
549 u_long mbase;
550 u_long msize;
551 int flags;
552{
553 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
554 flags);
555}
556
557int
558eisa_add_iospace(e_dev, iobase, iosize, flags)
559 struct eisa_device *e_dev;
560 u_long iobase;
561 u_long iosize;
562 int flags;
563{
564 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
565 iosize, flags);
566}
567
568static int
569eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count)
570 struct eisa_device *e_dev;
571 struct resvlist *head;
572 resvaddr_t *resvaddr;
573 int *reg_count;
574{
575 if (reg_state.in_registration) {
576 resvaddr_t *node;
577 /*
578 * Ensure that this resvaddr is actually in the devices'
579 * reservation list.
580 */
581 for(node = head->lh_first; node;
582 node = node->links.le_next) {
583 if (node == resvaddr) {
584 char buf[35];
585 char separator = ',';
586 char *string = buf;
587
588 if (*reg_count == 0) {
589 /* First time */
590 string += sprintf(string, " at");
591 }
592
593 if (node->size == 1
594 || (node->flags & RESVADDR_BITMASK))
595 sprintf(string, " 0x%lx", node->addr);
596 else
597 sprintf(string, " 0x%lx-0x%lx",
598 node->addr,
599 node->addr + node->size - 1);
600 eisa_reg_print(e_dev, buf,
601 *reg_count ? &separator : NULL);
602 (*reg_count)++;
603 return (0);
604 }
605 }
606 return (ENOENT);
607 }
608 return EPERM;
609}
610
611int
612eisa_reg_mspace(e_dev, resvaddr)
613 struct eisa_device *e_dev;
614 resvaddr_t *resvaddr;
615{
616#ifdef NOT_YET
617 /*
618 * Punt on conflict detection for the moment.
619 * I want to develop a generic routine to do
620 * this for all device types.
621 */
622 int checkthese = CC_MADDR;
623 if (haveseen_dev(dev, checkthese))
624 return -1;
625#endif
626 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr,
627 &(reg_state.num_maddrs)));
628}
629
630int
631eisa_reg_iospace(e_dev, resvaddr)
632 struct eisa_device *e_dev;
633 resvaddr_t *resvaddr;
634{
635#ifdef NOT_YET
636 /*
637 * Punt on conflict detection for the moment.
638 * I want to develop a generic routine to do
639 * this for all device types.
640 */
641 int checkthese = CC_IOADDR;
642 if (haveseen_dev(dev, checkthese))
643 return -1;
644#endif
645 return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr,
646 &(reg_state.num_ioaddrs)));
647}
648
649int
650eisa_registerdev(e_dev, driver)
651 struct eisa_device *e_dev;
652 struct eisa_driver *driver;
653{
654 e_dev->driver = driver; /* Driver now owns this device */
655 return (0);
656}
657