]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mca/mca_bus.c
This commit was generated by cvs2svn to compensate for changes in r50894,
[FreeBSD/FreeBSD.git] / 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$
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 resvaddr {
59         u_long  addr;                   /* start address */
60         u_long  size;                   /* size of reserved area */
61         int     flags;
62         struct resource *res;           /* resource manager handle */
63         LIST_ENTRY(resvaddr) links;     /* List links */
64 };
65
66 LIST_HEAD(resvlist, resvaddr); 
67
68 struct res_node {
69         int     num;
70         void    *desc;
71         TAILQ_ENTRY(res_node) links;
72 };
73
74 TAILQ_HEAD(nodelist, res_node);
75
76 struct mca_device {
77         mca_id_t        id;
78         u_int8_t        slot;
79         u_int8_t        enabled;
80         u_int8_t        pos[8];         /* Programable Option Select Regs. */
81
82         struct nodelist irqs;           /* list of reserved IRQs */
83         struct nodelist drqs;           /* list of reserved DRQs */
84         struct resvlist ioaddrs;        /* list of reserved I/O ranges */
85         struct resvlist maddrs;         /* list of reserved memory ranges */
86 };
87
88 static struct res_node *
89 mca_find_irq (struct mca_device * m_dev, int rid)
90 {
91         int                     i;
92         struct res_node *       irq;
93
94         for (i = 0, irq = TAILQ_FIRST(&m_dev->irqs);
95              i < rid && irq;
96              i++, irq = TAILQ_NEXT(irq, links))
97                 ;
98
99         if (irq)
100                 return (irq);
101         else
102                 return (NULL);
103 }
104
105 static struct res_node *
106 mca_find_drq (struct mca_device * m_dev, int rid)
107 {
108         int                     i;
109         struct res_node *       drq;
110
111         for (i = 0, drq = TAILQ_FIRST(&m_dev->drqs);
112              i < rid && drq;
113              i++, drq = TAILQ_NEXT(drq, links))
114                 ;
115
116         if (drq)
117                 return (drq);
118         else
119                 return (NULL);
120 }
121
122 static struct resvaddr *
123 mca_find_ioaddr (struct mca_device *m_dev, int rid)
124 {
125         int                     i;
126         struct resvaddr *       resv;
127
128         for (i = 0, resv = LIST_FIRST(&m_dev->ioaddrs);
129              i < rid && resv;
130              i++, resv = LIST_NEXT(resv, links))
131                 ;
132
133         return (resv);
134 }
135
136 static struct resvaddr *
137 mca_find_maddr (struct mca_device * m_dev, int rid)
138 {
139         int                     i;
140         struct resvaddr *       resv;
141
142         for (i = 0, resv = LIST_FIRST(&m_dev->maddrs);
143              i < rid && resv;
144              i++, resv = LIST_NEXT(resv, links))
145                 ;
146
147         return (resv);
148 }
149
150 /* Not supposed to use this function! */
151 void
152 mca_pos_set (dev, reg, data)
153         device_t        dev;
154         u_int8_t        reg;
155         u_int8_t        data;
156 {
157         struct mca_device *     m_dev = device_get_ivars(dev);
158         u_int8_t                slot = mca_get_slot(dev);
159
160         if ((slot > MCA_MAX_ADAPTERS) || (reg > MCA_POS7))
161                 return;
162
163         /* Disable motherboard setup */
164         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
165
166         /* Select adapter setup regs */
167         outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
168
169         /* Write the register */
170         outb(MCA_POS_REG(reg), data); 
171
172         /* Disable adapter setup */
173         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
174
175         /* Update the IVAR copy */
176         m_dev->pos[reg] = data;
177
178         return;
179 }
180
181 u_int8_t
182 mca_pos_get (dev, reg)
183         device_t        dev;
184         u_int8_t        reg;
185 {
186         u_int8_t        slot = mca_get_slot(dev);
187         u_int8_t        data = 0;
188
189         if ((slot > MCA_MAX_ADAPTERS) || (reg > MCA_POS7))
190                 return (0);
191
192         /* Disable motherboard setup */
193         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
194
195         switch (slot) {
196                 case MCA_MB_SCSI_SLOT:
197
198                         /* Disable adapter setup */
199                         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
200
201                         /* Select motherboard video setup regs */
202                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_SCSI);
203
204                         /* read the register */
205                         data = inb(MCA_POS_REG(reg));
206
207                         /* Disable motherboard setup */
208                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
209
210                         break;
211                 case MCA_MB_VIDEO_SLOT:
212                         /* Disable adapter setup */
213                         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
214
215                         /* Select motherboard scsi setup regs */
216                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_VIDEO);
217
218                         /* read the register */
219                         data = inb(MCA_POS_REG(reg));
220
221                         /* Disable motherboard setup */
222                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
223                         break;
224                 default:
225
226                         /* Select adapter setup regs */
227                         outb(MCA_ADAP_SETUP_REG,
228                              ((slot & 0x0f) | MCA_ADAP_SET));
229
230                         /* read the register */
231                         data = inb(MCA_POS_REG(reg));
232
233                         /* Disable adapter setup */
234                         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
235                         break;
236         }
237
238         return (data);
239 }
240
241 const char *
242 mca_match_id (id, mca_devs)
243         u_int16_t               id;
244         struct mca_ident *      mca_devs;
245 {
246         struct mca_ident *      m = mca_devs;
247         while(m->name != NULL) {
248                 if (id == m->id)
249                         return (m->name);
250                 m++;
251         }
252         return (NULL);
253 }
254
255 u_int8_t
256 mca_pos_read (dev, reg)
257         device_t                dev;
258         u_int8_t                reg;
259 {
260         struct mca_device *     m_dev = device_get_ivars(dev);
261
262         if (reg > MCA_POS7)
263                 return (0);
264
265         return (m_dev->pos[reg]);
266 }
267
268 int
269 mca_add_irq (dev, irq)
270         device_t                dev;
271         int                     irq;
272 {
273         struct mca_device *     m_dev = device_get_ivars(dev);
274         struct res_node *       irq_info;
275
276         irq_info = (struct res_node *)malloc(sizeof(*irq_info),
277                                         M_DEVBUF, M_NOWAIT);
278         if (irq_info == NULL)
279                 return (1);
280
281         irq_info->num = irq;
282         irq_info->desc = NULL;
283         TAILQ_INSERT_TAIL(&m_dev->irqs, irq_info, links);
284
285         return (0);
286 }
287
288 int
289 mca_add_drq (dev, drq)
290         device_t        dev;
291         int             drq;
292 {
293         struct mca_device *     m_dev = device_get_ivars(dev);
294         struct res_node *       drq_info;
295
296         drq_info = (struct res_node *)malloc(sizeof(*drq_info),
297                                         M_DEVBUF, M_NOWAIT);
298         if (drq_info == NULL)
299                 return (1);
300
301         drq_info->num = drq;
302         drq_info->desc = NULL;
303         TAILQ_INSERT_TAIL(&m_dev->drqs, drq_info, links);
304
305         return (0);
306 }
307
308 static int
309 mca_add_resvaddr (struct mca_device * m_dev, struct resvlist * head,
310                   u_long base, u_long size, int flags)
311 {
312         struct resvaddr *       reservation;
313
314         reservation = (struct resvaddr *)malloc(sizeof(struct resvaddr),
315                                            M_DEVBUF, M_NOWAIT);
316         if(!reservation)
317                 return (ENOMEM);
318
319         reservation->addr = base;
320         reservation->size = size;
321         reservation->flags = flags;
322
323         if (!head->lh_first) {
324                 LIST_INSERT_HEAD(head, reservation, links);
325         } else {
326                 struct resvaddr *       node;
327                 for(node = head->lh_first; node; node = node->links.le_next) {
328                         if (node->addr > reservation->addr) {
329                                 /*
330                                  * List is sorted in increasing
331                                  * address order.
332                                  */
333                                 LIST_INSERT_BEFORE(node, reservation, links);
334                                 break;
335                         }
336
337                         if (node->addr == reservation->addr) {
338                                 /*
339                                  * If the entry we want to add
340                                  * matches any already in here,
341                                  * fail.
342                                  */
343                                 free(reservation, M_DEVBUF);
344                                 return (EEXIST);
345                         }
346
347                         if (!node->links.le_next) {
348                                 LIST_INSERT_AFTER(node, reservation, links);
349                                 break;
350                         }
351                 }
352         }
353         return (0);
354 }
355
356 int
357 mca_add_mspace (dev, mbase, msize, flags) 
358         device_t                dev;
359         u_long                  mbase;
360         u_long                  msize;
361         int                     flags;
362 {
363         struct mca_device *m_dev = device_get_ivars(dev);
364
365         return (mca_add_resvaddr(m_dev, &(m_dev->maddrs),
366                                  mbase, msize, flags));
367 }
368
369 int
370 mca_add_iospace (dev, iobase, iosize, flags) 
371         device_t                dev;
372         u_long                  iobase;
373         u_long                  iosize;
374         int                     flags;
375 {
376         struct mca_device *     m_dev = device_get_ivars(dev);
377
378         return (mca_add_resvaddr(m_dev, &(m_dev->ioaddrs),
379                                  iobase, iosize, flags));
380 }
381
382 static int
383 mca_probe (device_t dev)
384 {
385         struct mca_device *     m_dev = NULL;
386         int                     devices_found = 0;
387         u_int8_t                slot;
388         u_int8_t                reg;
389
390         device_set_desc(dev, "MCA bus");
391
392         /* Disable adapter setup */
393         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
394         /* Disable motherboard setup */
395         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
396
397         if (bootverbose) {
398                 printf("POS REG     00 01 02 03 04 05 06 07\n");
399                 printf("-----------------------------------\n");
400         }
401
402         for (slot = 0; slot < MCA_MAX_SLOTS; slot++) {
403
404                 if (!m_dev) {
405                         m_dev = (struct mca_device *)malloc(sizeof(*m_dev),
406                                                             M_DEVBUF, M_NOWAIT);
407                         if (!m_dev) {
408                                 device_printf(dev, "cannot malloc mca_device");
409                                 break;
410                         }
411                 }
412                 bzero(m_dev, sizeof(*m_dev));
413
414                 /* Select adapter setup regs */
415                 outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
416
417                 /* Read the POS registers */
418                 for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
419                         m_dev->pos[reg] = inb(MCA_POS_REG(reg));
420                 }
421
422                 /* Disable adapter setup */
423                 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
424
425                 if (bootverbose) {
426                         printf("mca slot %d:", slot + 1);       
427                         for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
428                                 printf(" %02x", m_dev->pos[reg]);
429                         }
430                         printf("\n");
431                 }
432
433                 m_dev->id = (u_int16_t)m_dev->pos[MCA_POS0] |
434                             ((u_int16_t)m_dev->pos[MCA_POS1] << 8);
435
436                 if (m_dev->id == 0xffff) {
437                         continue;
438                 }
439
440                 devices_found++;
441
442                 m_dev->enabled = (m_dev->pos[MCA_POS2] & MCA_POS2_ENABLE);
443                 m_dev->slot = slot;
444
445                 /* Initialize our lists of reserved addresses */
446                 LIST_INIT(&(m_dev->ioaddrs));
447                 LIST_INIT(&(m_dev->maddrs));
448                 TAILQ_INIT(&(m_dev->irqs));
449                 TAILQ_INIT(&(m_dev->drqs));
450
451                 device_add_child(dev, NULL, -1, m_dev);
452                 m_dev = NULL;
453         }
454
455         if (m_dev) {
456                 free(m_dev, M_DEVBUF);
457         }
458
459         return (devices_found ? 0 : ENXIO);
460 }
461
462 static void
463 mca_reg_print (dev, string, separator, column)
464         device_t        dev;
465         char *          string;
466         char *          separator;
467         int *           column;
468 {
469         int             length = strlen(string);
470
471         length += (separator ? 2 : 1);
472
473         if (((*column) + length) >= MAX_COL) {
474                 printf("\n");
475                 (*column) = 0;
476         } else if ((*column) != 0) {
477                 if (separator) {
478                         printf("%c", *separator);
479                         (*column)++;
480                 }
481                 printf(" ");
482                 (*column)++;
483         }
484
485         if ((*column) == 0) {
486                 (*column) += device_printf(dev, "%s", string);
487         } else {
488                 (*column) += printf("%s", string);
489         }
490
491         return;
492 }
493
494 static int
495 mca_print_child (device_t dev, device_t child)
496 {
497         char                    buf[81];
498         struct mca_device *     m_dev = device_get_ivars(child);
499         int                     rid;
500         struct res_node *       node;
501         struct resvaddr *       resv;
502         char                    separator = ',';
503         int                     column = 0;
504         int                     retval = 0;
505
506         if (device_get_desc(child)) {
507                 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
508                 mca_reg_print(child, buf, NULL, &column);
509         }
510
511         rid = 0;
512         while ((resv = mca_find_ioaddr(m_dev, rid++))) {
513                 if (resv->size == 1) {
514                         snprintf(buf, sizeof(buf), "%s%lx",
515                                 ((rid == 1) ? "io 0x" : "0x"),
516                                 resv->addr);
517                 } else {
518                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
519                                 ((rid == 1) ? "io 0x" : "0x"),
520                                 resv->addr,
521                                 (resv->addr + resv->size));
522                 }
523                 mca_reg_print(child, buf,
524                         ((rid == 2) ? &separator : NULL), &column);
525         }
526
527         rid = 0;
528         while ((resv = mca_find_maddr(m_dev, rid++))) {
529                 if (resv->size == 1) {
530                         snprintf(buf, sizeof(buf), "%s%lx",
531                                 ((rid == 1) ? "mem 0x" : "0x"),
532                                 resv->addr);
533                 } else {
534                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
535                                 ((rid == 1) ? "mem 0x" : "0x"),
536                                 resv->addr,
537                                 (resv->addr + resv->size));
538                 }
539                 mca_reg_print(child, buf,
540                         ((rid == 2) ? &separator : NULL), &column);
541         }
542
543         rid = 0;
544         while ((node = mca_find_irq(m_dev, rid++)) != NULL) {
545                 snprintf(buf, sizeof(buf), "irq %d", node->num);
546                 mca_reg_print(child, buf,
547                         ((rid == 1) ? &separator : NULL), &column);
548         }
549
550         rid = 0;
551         while ((node = mca_find_drq(m_dev, rid++)) != NULL) {
552                 snprintf(buf, sizeof(buf), "drq %x", node->num);
553                 mca_reg_print(child, buf,
554                         ((rid == 1) ? &separator : NULL), &column);
555         }
556
557         snprintf(buf, sizeof(buf), "on %s id %04x slot %d\n",
558                 device_get_nameunit(dev),
559                 mca_get_id(child), mca_get_slot(child)+1);
560         mca_reg_print(child, buf, NULL, &column);
561
562         return (retval);
563 }
564
565 static void
566 mca_probe_nomatch (device_t dev, device_t child)
567 {
568         mca_id_t        mca_id = mca_get_id(child);
569         u_int8_t        slot = mca_get_slot(child);
570         u_int8_t        enabled = mca_get_enabled(child);
571
572         device_printf(dev, "unknown card (id 0x%04x, %s) at slot %d\n",
573                 mca_id,
574                 (enabled ? "enabled" : "disabled"),
575                 slot + 1);
576
577         return;
578 }
579
580 static int
581 mca_read_ivar (device_t dev, device_t child, int which, u_long * result)
582 {
583         struct mca_device *     m_dev = device_get_ivars(child);
584         struct res_node *       node;
585
586         switch (which) {
587                 case MCA_IVAR_SLOT:
588                         *result = m_dev->slot;
589                         break;
590                 case MCA_IVAR_ID:
591                         *result = m_dev->id;
592                         break;
593                 case MCA_IVAR_ENABLED:
594                         *result = m_dev->enabled;
595                         break;
596                 case MCA_IVAR_IRQ:
597                         if ((node = mca_find_irq(m_dev, 0)))
598                                 *result = node->num;
599                         else 
600                                 *result = -1;
601                         break;
602                 case MCA_IVAR_DRQ:
603                         if ((node = mca_find_drq(m_dev, 0)))
604                                 *result = node->num;
605                         else 
606                                 *result = -1;
607                         break;
608                 default:
609                         return (ENOENT);
610                         break;
611         }
612
613         return (0);
614 }
615
616 static int
617 mca_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
618 {
619         return (EINVAL);
620 }
621
622 static struct resource *
623 mca_alloc_resource (device_t dev, device_t child, int type, int *rid,
624                     u_long start, u_long end, u_long count, u_int flags)
625 {
626         struct mca_device *     m_dev = device_get_ivars(child);
627         struct resource *       rv;
628         struct resource **      rvp = NULL;
629         struct resvaddr *       resv;
630         struct res_node *       node;
631         int                     isdefault;
632
633         isdefault = ((device_get_parent(child) == dev) 
634                         && (start == 0UL)
635                         && (end == ~0UL));
636
637         switch (type) {
638                 case SYS_RES_IRQ:
639                         if (isdefault) {
640                                 node = mca_find_irq(m_dev, *rid);
641                                 if (!node)
642                                         return (0);
643
644                                 start = end = node->num;
645                                 count = 1;
646                                 flags |= RF_SHAREABLE;
647                         }
648                         break;
649                 case SYS_RES_DRQ:
650                         if (isdefault) {
651                                 node = mca_find_drq(m_dev, *rid);
652                                 if (!node)
653                                         return (0);
654
655                                 start = end = node->num;
656                                 count = 1;
657                         }
658                         break;
659                 case SYS_RES_MEMORY:
660                         if (isdefault) {
661                                 resv = mca_find_maddr(m_dev, *rid);
662                                 if (!resv)
663                                         return (0);
664
665                                 start = resv->addr;
666                                 end = resv->addr + resv->size;
667                                 count = resv->size;
668                                 rvp = &resv->res;
669                         }
670                         break;
671                 case SYS_RES_IOPORT:
672                         if (isdefault) {
673                                 resv = mca_find_ioaddr(m_dev, *rid);
674                                 if (!resv)
675                                         return (0);
676
677                                 start = resv->addr;
678                                 end = resv->addr + resv->size;
679                                 count = resv->size;
680                                 rvp = &resv->res;
681                         }
682                         break;
683                 default:
684                         return (0);
685                         break;
686         }
687
688         rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
689                                 type, rid, start, end, count, flags);
690
691         if (rvp)
692                 *rvp = rv;
693
694         return (rv);
695 }
696
697 static int
698 mca_release_resource (device_t dev, device_t child, int type, int rid,
699                       struct resource * r)
700 {
701         struct mca_device *     m_dev = device_get_ivars(child);
702         struct resvaddr *       resv = NULL;
703         int                     rv;
704         int                     isdefault;
705
706         isdefault = (device_get_parent(child) == dev);
707
708         switch (type) {
709                 case SYS_RES_IRQ:
710                         if (mca_find_irq(m_dev, rid) == NULL)
711                                 return (EINVAL);
712                         break;
713                 case SYS_RES_DRQ:
714                         if (mca_find_drq(m_dev, rid) == NULL)
715                                 return (EINVAL);
716                         break;
717                 case SYS_RES_MEMORY:
718                         if (isdefault) {
719                                 resv = mca_find_maddr(m_dev, rid);
720                         }
721                         break;
722                 case SYS_RES_IOPORT:
723                         if (isdefault) {
724                                 resv = mca_find_ioaddr(m_dev, rid);
725                         }
726                         break;
727                 default:
728                         break;
729         }
730
731         rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
732
733         if (rv == 0) {
734                 if (resv)
735                         resv->res = 0;
736         }
737
738         return (rv);
739 }
740
741 static device_method_t mca_methods[] = {
742         /* Device interface */
743         DEVMETHOD(device_probe,         mca_probe),
744         DEVMETHOD(device_attach,        bus_generic_attach),
745         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
746         DEVMETHOD(device_suspend,       bus_generic_suspend),
747         DEVMETHOD(device_resume,        bus_generic_resume),
748
749         /* Bus interface */
750         DEVMETHOD(bus_print_child,      mca_print_child),
751         DEVMETHOD(bus_probe_nomatch,    mca_probe_nomatch),
752         DEVMETHOD(bus_read_ivar,        mca_read_ivar),
753         DEVMETHOD(bus_write_ivar,       mca_write_ivar),
754         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
755         DEVMETHOD(bus_alloc_resource,   mca_alloc_resource),
756         DEVMETHOD(bus_release_resource, mca_release_resource),
757         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
758         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
759         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
760         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),     
761
762         { 0, 0 }
763 };
764
765 static driver_t mca_driver = {       
766         "mca",
767         mca_methods,
768         1,              /* no softc */
769 };
770
771 static devclass_t mca_devclass;
772
773 DRIVER_MODULE(mca, nexus, mca_driver, mca_devclass, 0, 0);