FreeBSD/Linux Kernel Cross Reference
sys/dev/mca/mca_bus.c
1 /*-
2 * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: releng/5.0/sys/dev/mca/mca_bus.c 104015 2002-09-26 18:40:06Z jhb $
27 */
28
29 /*
30 * References:
31 * The CMU Mach3 microkernel
32 * NetBSD MCA patches by Scott Telford
33 * Linux MCA code.
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/queue.h>
39 #include <sys/malloc.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/bus.h>
43
44 #include <machine/limits.h>
45 #include <machine/bus.h>
46 #include <machine/resource.h>
47 #include <sys/rman.h>
48
49 #include <dev/mca/mca_busreg.h>
50 #include <dev/mca/mca_busvar.h>
51
52 #include <sys/interrupt.h>
53
54 #define MAX_COL 79
55
56 static void mca_reg_print (device_t, char *, char *, int *);
57
58 struct mca_device {
59 struct resource_list rl; /* Resources */
60
61 mca_id_t id;
62 u_int8_t slot;
63 u_int8_t enabled;
64 u_int8_t pos[8]; /* Programable Option Select Regs. */
65 };
66
67 /* Not supposed to use this function! */
68 void
69 mca_pos_set (dev, reg, data)
70 device_t dev;
71 u_int8_t reg;
72 u_int8_t data;
73 {
74 struct mca_device * m_dev = device_get_ivars(dev);
75 u_int8_t slot = mca_get_slot(dev);
76
77 if ((slot > MCA_MAX_ADAPTERS) || (reg > MCA_POS7))
78 return;
79
80 /* Disable motherboard setup */
81 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
82
83 /* Select adapter setup regs */
84 outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
85
86 /* Write the register */
87 outb(MCA_POS_REG(reg), data);
88
89 /* Disable adapter setup */
90 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
91
92 /* Update the IVAR copy */
93 m_dev->pos[reg] = data;
94
95 return;
96 }
97
98 u_int8_t
99 mca_pos_get (dev, reg)
100 device_t dev;
101 u_int8_t reg;
102 {
103 u_int8_t slot = mca_get_slot(dev);
104 u_int8_t data = 0;
105
106 if ((slot > MCA_MAX_ADAPTERS) || (reg > MCA_POS7))
107 return (0);
108
109 /* Disable motherboard setup */
110 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
111
112 switch (slot) {
113 case MCA_MB_SCSI_SLOT:
114
115 /* Disable adapter setup */
116 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
117
118 /* Select motherboard video setup regs */
119 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_SCSI);
120
121 /* read the register */
122 data = inb(MCA_POS_REG(reg));
123
124 /* Disable motherboard setup */
125 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
126
127 break;
128 case MCA_MB_VIDEO_SLOT:
129 /* Disable adapter setup */
130 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
131
132 /* Select motherboard scsi setup regs */
133 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_VIDEO);
134
135 /* read the register */
136 data = inb(MCA_POS_REG(reg));
137
138 /* Disable motherboard setup */
139 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
140 break;
141 default:
142
143 /* Select adapter setup regs */
144 outb(MCA_ADAP_SETUP_REG,
145 ((slot & 0x0f) | MCA_ADAP_SET));
146
147 /* read the register */
148 data = inb(MCA_POS_REG(reg));
149
150 /* Disable adapter setup */
151 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
152 break;
153 }
154
155 return (data);
156 }
157
158 const char *
159 mca_match_id (id, mca_devs)
160 u_int16_t id;
161 struct mca_ident * mca_devs;
162 {
163 struct mca_ident * m = mca_devs;
164 while(m->name != NULL) {
165 if (id == m->id)
166 return (m->name);
167 m++;
168 }
169 return (NULL);
170 }
171
172 u_int8_t
173 mca_pos_read (dev, reg)
174 device_t dev;
175 u_int8_t reg;
176 {
177 struct mca_device * m_dev = device_get_ivars(dev);
178
179 if (reg > MCA_POS7)
180 return (0);
181
182 return (m_dev->pos[reg]);
183 }
184
185 void
186 mca_add_irq (dev, irq)
187 device_t dev;
188 int irq;
189 {
190 struct mca_device * m_dev = device_get_ivars(dev);
191 int rid = 0;
192
193 while (resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid)) rid++;
194 resource_list_add(&(m_dev->rl), SYS_RES_IRQ, rid, irq, irq, 1);
195
196 return;
197 }
198
199 void
200 mca_add_drq (dev, drq)
201 device_t dev;
202 int drq;
203 {
204 struct mca_device * m_dev = device_get_ivars(dev);
205 int rid = 0;
206
207 while (resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid)) rid++;
208 resource_list_add(&(m_dev->rl), SYS_RES_DRQ, rid, drq, drq, 1);
209
210 return;
211 }
212
213 void
214 mca_add_mspace (dev, mbase, msize)
215 device_t dev;
216 u_long mbase;
217 u_long msize;
218 {
219 struct mca_device * m_dev = device_get_ivars(dev);
220 int rid = 0;
221
222 while (resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid)) rid++;
223 resource_list_add(&(m_dev->rl), SYS_RES_MEMORY, rid,
224 mbase, (mbase + msize), msize);
225
226 return;
227 }
228
229 void
230 mca_add_iospace (dev, iobase, iosize)
231 device_t dev;
232 u_long iobase;
233 u_long iosize;
234 {
235 struct mca_device * m_dev = device_get_ivars(dev);
236 int rid = 0;
237
238 while (resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid)) rid++;
239 resource_list_add(&(m_dev->rl), SYS_RES_IOPORT, rid,
240 iobase, (iobase + iosize), iosize);
241
242 return;
243 }
244
245 static int
246 mca_probe (device_t dev)
247 {
248 device_t child;
249 struct mca_device * m_dev = NULL;
250 int devices_found = 0;
251 u_int8_t slot;
252 u_int8_t reg;
253
254 device_set_desc(dev, "MCA bus");
255
256 /* Disable adapter setup */
257 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
258 /* Disable motherboard setup */
259 outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
260
261 if (bootverbose) {
262 printf("POS REG 00 01 02 03 04 05 06 07\n");
263 printf("-----------------------------------\n");
264 }
265
266 for (slot = 0; slot < MCA_MAX_SLOTS; slot++) {
267
268 if (!m_dev) {
269 m_dev = (struct mca_device *)malloc(sizeof(*m_dev),
270 M_DEVBUF, M_NOWAIT);
271 if (!m_dev) {
272 device_printf(dev, "cannot malloc mca_device");
273 break;
274 }
275 }
276 bzero(m_dev, sizeof(*m_dev));
277
278 /* Select adapter setup regs */
279 outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
280
281 /* Read the POS registers */
282 for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
283 m_dev->pos[reg] = inb(MCA_POS_REG(reg));
284 }
285
286 /* Disable adapter setup */
287 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
288
289 if (bootverbose) {
290 printf("mca slot %d:", slot + 1);
291 for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
292 printf(" %02x", m_dev->pos[reg]);
293 }
294 printf("\n");
295 }
296
297 m_dev->id = (u_int16_t)m_dev->pos[MCA_POS0] |
298 ((u_int16_t)m_dev->pos[MCA_POS1] << 8);
299
300 if (m_dev->id == 0xffff) {
301 continue;
302 }
303
304 devices_found++;
305
306 m_dev->enabled = (m_dev->pos[MCA_POS2] & MCA_POS2_ENABLE);
307 m_dev->slot = slot;
308
309 resource_list_init(&(m_dev->rl));
310
311 child = device_add_child(dev, NULL, -1);
312 device_set_ivars(child, m_dev);
313
314 m_dev = NULL;
315 }
316
317 if (m_dev) {
318 free(m_dev, M_DEVBUF);
319 }
320
321 return (devices_found ? 0 : ENXIO);
322 }
323
324 static void
325 mca_reg_print (dev, string, separator, column)
326 device_t dev;
327 char * string;
328 char * separator;
329 int * column;
330 {
331 int length = strlen(string);
332
333 length += (separator ? 2 : 1);
334
335 if (((*column) + length) >= MAX_COL) {
336 printf("\n");
337 (*column) = 0;
338 } else if ((*column) != 0) {
339 if (separator) {
340 printf("%c", *separator);
341 (*column)++;
342 }
343 printf(" ");
344 (*column)++;
345 }
346
347 if ((*column) == 0) {
348 (*column) += device_printf(dev, "%s", string);
349 } else {
350 (*column) += printf("%s", string);
351 }
352
353 return;
354 }
355
356 static int
357 mca_print_child (device_t dev, device_t child)
358 {
359 char buf[MAX_COL+1];
360 struct mca_device * m_dev = device_get_ivars(child);
361 int rid;
362 struct resource_list_entry * rle;
363 char separator = ',';
364 int column = 0;
365 int retval = 0;
366
367 if (device_get_desc(child)) {
368 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
369 mca_reg_print(child, buf, NULL, &column);
370 }
371
372 rid = 0;
373 while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid++))) {
374 if (rle->count == 1) {
375 snprintf(buf, sizeof(buf), "%s%lx",
376 ((rid == 1) ? "io 0x" : "0x"),
377 rle->start);
378 } else {
379 snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
380 ((rid == 1) ? "io 0x" : "0x"),
381 rle->start,
382 (rle->start + rle->count));
383 }
384 mca_reg_print(child, buf,
385 ((rid == 2) ? &separator : NULL), &column);
386 }
387
388 rid = 0;
389 while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid++))) {
390 if (rle->count == 1) {
391 snprintf(buf, sizeof(buf), "%s%lx",
392 ((rid == 1) ? "mem 0x" : "0x"),
393 rle->start);
394 } else {
395 snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
396 ((rid == 1) ? "mem 0x" : "0x"),
397 rle->start,
398 (rle->start + rle->count));
399 }
400 mca_reg_print(child, buf,
401 ((rid == 2) ? &separator : NULL), &column);
402 }
403
404 rid = 0;
405 while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid++))) {
406 snprintf(buf, sizeof(buf), "irq %ld", rle->start);
407 mca_reg_print(child, buf,
408 ((rid == 1) ? &separator : NULL), &column);
409 }
410
411 rid = 0;
412 while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid++))) {
413 snprintf(buf, sizeof(buf), "drq %lx", rle->start);
414 mca_reg_print(child, buf,
415 ((rid == 1) ? &separator : NULL), &column);
416 }
417
418 snprintf(buf, sizeof(buf), "on %s id %04x slot %d\n",
419 device_get_nameunit(dev),
420 mca_get_id(child), mca_get_slot(child)+1);
421 mca_reg_print(child, buf, NULL, &column);
422
423 return (retval);
424 }
425
426 static void
427 mca_probe_nomatch (device_t dev, device_t child)
428 {
429 mca_id_t mca_id = mca_get_id(child);
430 u_int8_t slot = mca_get_slot(child);
431 u_int8_t enabled = mca_get_enabled(child);
432
433 device_printf(dev, "unknown card (id 0x%04x, %s) at slot %d\n",
434 mca_id,
435 (enabled ? "enabled" : "disabled"),
436 slot + 1);
437
438 return;
439 }
440
441 static int
442 mca_read_ivar (device_t dev, device_t child, int which, u_long * result)
443 {
444 struct mca_device * m_dev = device_get_ivars(child);
445
446 switch (which) {
447 case MCA_IVAR_SLOT:
448 *result = m_dev->slot;
449 break;
450 case MCA_IVAR_ID:
451 *result = m_dev->id;
452 break;
453 case MCA_IVAR_ENABLED:
454 *result = m_dev->enabled;
455 break;
456 default:
457 return (ENOENT);
458 break;
459 }
460
461 return (0);
462 }
463
464 static struct resource *
465 mca_alloc_resource (device_t dev, device_t child, int type, int *rid,
466 u_long start, u_long end, u_long count, u_int flags)
467 {
468 struct mca_device * m_dev = device_get_ivars(child);
469 struct resource_list_entry * rle;
470 int isdefault;
471 int passthrough;
472
473 isdefault = (start == 0UL && end == ~0UL);
474 passthrough = (device_get_parent(child) != dev);
475
476 if (!passthrough && !isdefault) {
477 rle = resource_list_find(&(m_dev->rl), type, *rid);
478 if (!rle) {
479 resource_list_add(&(m_dev->rl), type, *rid,
480 start, end, count);
481 }
482 }
483
484 if (type == SYS_RES_IRQ) {
485 flags |= RF_SHAREABLE;
486 }
487
488 return (resource_list_alloc(&(m_dev->rl), dev, child, type, rid,
489 start, end, count, flags));
490 }
491
492 static struct resource_list *
493 mca_get_resource_list (device_t dev, device_t child)
494 {
495 struct mca_device * m_dev = device_get_ivars(child);
496 struct resource_list * rl = &m_dev->rl;
497
498 if (!rl)
499 return (NULL);
500
501 return (rl);
502 }
503
504 static device_method_t mca_methods[] = {
505 /* Device interface */
506 DEVMETHOD(device_probe, mca_probe),
507 DEVMETHOD(device_attach, bus_generic_attach),
508 DEVMETHOD(device_shutdown, bus_generic_shutdown),
509 DEVMETHOD(device_suspend, bus_generic_suspend),
510 DEVMETHOD(device_resume, bus_generic_resume),
511
512 /* Bus interface */
513 DEVMETHOD(bus_print_child, mca_print_child),
514 DEVMETHOD(bus_probe_nomatch, mca_probe_nomatch),
515 DEVMETHOD(bus_read_ivar, mca_read_ivar),
516 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
517 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
518 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
519 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
520
521 DEVMETHOD(bus_get_resource_list,mca_get_resource_list),
522 DEVMETHOD(bus_alloc_resource, mca_alloc_resource),
523 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
524 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
525 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
526 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
527 DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
528 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
529
530 { 0, 0 }
531 };
532
533 static driver_t mca_driver = {
534 "mca",
535 mca_methods,
536 1, /* no softc */
537 };
538
539 static devclass_t mca_devclass;
540
541 DRIVER_MODULE(mca, legacy, mca_driver, mca_devclass, 0, 0);
Cache object: 7bdded951712e2f9b4cc948a5959e76d
|