Merge from vendor branch BIND:
[dragonfly.git] / sys / bus / 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: src/sys/dev/mca/mca_bus.c,v 1.7.2.1 2000/03/17 23:55:48 peter Exp $
27  * $DragonFly: src/sys/bus/mca/Attic/mca_bus.c,v 1.5 2004/04/07 05:54:39 dillon Exp $
28  */
29
30 /*
31  * References:
32  *              The CMU Mach3 microkernel
33  *              NetBSD MCA patches by Scott Telford
34  *              Linux MCA code.
35  */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/queue.h>
40 #include <sys/malloc.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/bus.h>
44  
45 #include <machine/limits.h>
46 #include <machine/bus.h>              
47 #include <machine/resource.h>
48 #include <sys/rman.h>
49
50 #include "mca_busreg.h"
51 #include "mca_busvar.h"
52
53 #include <sys/interrupt.h>
54
55 #define MAX_COL  79
56
57 static void     mca_reg_print   (device_t, char *, char *, int *);
58
59 struct mca_device {
60         struct resource_list rl;        /* Resources */
61
62         mca_id_t        id;
63         u_int8_t        slot;
64         u_int8_t        enabled;
65         u_int8_t        pos[8];         /* Programable Option Select Regs. */
66 };
67
68 /* Not supposed to use this function! */
69 void
70 mca_pos_set (dev, reg, data)
71         device_t        dev;
72         u_int8_t        reg;
73         u_int8_t        data;
74 {
75         struct mca_device *     m_dev = device_get_ivars(dev);
76         u_int8_t                slot = mca_get_slot(dev);
77
78         if ((slot > MCA_MAX_ADAPTERS) || (reg > MCA_POS7))
79                 return;
80
81         /* Disable motherboard setup */
82         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
83
84         /* Select adapter setup regs */
85         outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
86
87         /* Write the register */
88         outb(MCA_POS_REG(reg), data); 
89
90         /* Disable adapter setup */
91         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
92
93         /* Update the IVAR copy */
94         m_dev->pos[reg] = data;
95
96         return;
97 }
98
99 u_int8_t
100 mca_pos_get (dev, reg)
101         device_t        dev;
102         u_int8_t        reg;
103 {
104         u_int8_t        slot = mca_get_slot(dev);
105         u_int8_t        data = 0;
106
107         if ((slot > MCA_MAX_ADAPTERS) || (reg > MCA_POS7))
108                 return (0);
109
110         /* Disable motherboard setup */
111         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
112
113         switch (slot) {
114                 case MCA_MB_SCSI_SLOT:
115
116                         /* Disable adapter setup */
117                         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
118
119                         /* Select motherboard video setup regs */
120                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_SCSI);
121
122                         /* read the register */
123                         data = inb(MCA_POS_REG(reg));
124
125                         /* Disable motherboard setup */
126                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
127
128                         break;
129                 case MCA_MB_VIDEO_SLOT:
130                         /* Disable adapter setup */
131                         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
132
133                         /* Select motherboard scsi setup regs */
134                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_VIDEO);
135
136                         /* read the register */
137                         data = inb(MCA_POS_REG(reg));
138
139                         /* Disable motherboard setup */
140                         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
141                         break;
142                 default:
143
144                         /* Select adapter setup regs */
145                         outb(MCA_ADAP_SETUP_REG,
146                              ((slot & 0x0f) | MCA_ADAP_SET));
147
148                         /* read the register */
149                         data = inb(MCA_POS_REG(reg));
150
151                         /* Disable adapter setup */
152                         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
153                         break;
154         }
155
156         return (data);
157 }
158
159 const char *
160 mca_match_id (id, mca_devs)
161         u_int16_t               id;
162         struct mca_ident *      mca_devs;
163 {
164         struct mca_ident *      m = mca_devs;
165         while(m->name != NULL) {
166                 if (id == m->id)
167                         return (m->name);
168                 m++;
169         }
170         return (NULL);
171 }
172
173 u_int8_t
174 mca_pos_read (dev, reg)
175         device_t                dev;
176         u_int8_t                reg;
177 {
178         struct mca_device *     m_dev = device_get_ivars(dev);
179
180         if (reg > MCA_POS7)
181                 return (0);
182
183         return (m_dev->pos[reg]);
184 }
185
186 void
187 mca_add_irq (dev, irq)
188         device_t                dev;
189         int                     irq;
190 {
191         struct mca_device *     m_dev = device_get_ivars(dev);
192         int                     rid = 0;
193
194         while (resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid)) rid++;
195         resource_list_add(&(m_dev->rl), SYS_RES_IRQ, rid, irq, irq, 1);
196
197         return;
198 }
199
200 void
201 mca_add_drq (dev, drq)
202         device_t                dev;
203         int                     drq;
204 {
205         struct mca_device *     m_dev = device_get_ivars(dev);
206         int                     rid = 0;
207
208         while (resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid)) rid++;
209         resource_list_add(&(m_dev->rl), SYS_RES_DRQ, rid, drq, drq, 1);
210
211         return;
212 }
213
214 void
215 mca_add_mspace (dev, mbase, msize) 
216         device_t                dev;
217         u_long                  mbase;
218         u_long                  msize;
219 {
220         struct mca_device *     m_dev = device_get_ivars(dev);
221         int                     rid = 0;
222
223         while (resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid)) rid++;
224         resource_list_add(&(m_dev->rl), SYS_RES_MEMORY, rid,
225                 mbase, (mbase + msize), msize);
226
227         return;
228 }
229
230 void
231 mca_add_iospace (dev, iobase, iosize) 
232         device_t                dev;
233         u_long                  iobase;
234         u_long                  iosize;
235 {
236         struct mca_device *     m_dev = device_get_ivars(dev);
237         int                     rid = 0;
238
239         while (resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid)) rid++;
240         resource_list_add(&(m_dev->rl), SYS_RES_IOPORT, rid,
241                 iobase, (iobase + iosize), iosize);
242
243         return;
244 }
245
246 static int
247 mca_probe (device_t dev)
248 {
249         device_t                child;
250         struct mca_device *     m_dev = NULL;
251         int                     devices_found = 0;
252         u_int8_t                slot;
253         u_int8_t                reg;
254
255         device_set_desc(dev, "MCA bus");
256
257         /* Disable adapter setup */
258         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
259         /* Disable motherboard setup */
260         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
261
262         if (bootverbose) {
263                 printf("POS REG     00 01 02 03 04 05 06 07\n");
264                 printf("-----------------------------------\n");
265         }
266
267         for (slot = 0; slot < MCA_MAX_SLOTS; slot++) {
268
269                 if (m_dev == NULL)
270                         m_dev = malloc(sizeof(*m_dev), M_DEVBUF, M_WAITOK);
271                 bzero(m_dev, sizeof(*m_dev));
272
273                 /* Select adapter setup regs */
274                 outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
275
276                 /* Read the POS registers */
277                 for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
278                         m_dev->pos[reg] = inb(MCA_POS_REG(reg));
279                 }
280
281                 /* Disable adapter setup */
282                 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
283
284                 if (bootverbose) {
285                         printf("mca slot %d:", slot + 1);       
286                         for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
287                                 printf(" %02x", m_dev->pos[reg]);
288                         }
289                         printf("\n");
290                 }
291
292                 m_dev->id = (u_int16_t)m_dev->pos[MCA_POS0] |
293                             ((u_int16_t)m_dev->pos[MCA_POS1] << 8);
294
295                 if (m_dev->id == 0xffff) {
296                         continue;
297                 }
298
299                 devices_found++;
300
301                 m_dev->enabled = (m_dev->pos[MCA_POS2] & MCA_POS2_ENABLE);
302                 m_dev->slot = slot;
303
304                 resource_list_init(&(m_dev->rl));
305
306                 child = device_add_child(dev, NULL, -1);
307                 device_set_ivars(child, m_dev);
308
309                 m_dev = NULL;
310         }
311
312         if (m_dev) {
313                 free(m_dev, M_DEVBUF);
314         }
315
316         return (devices_found ? 0 : ENXIO);
317 }
318
319 static void
320 mca_reg_print (dev, string, separator, column)
321         device_t        dev;
322         char *          string;
323         char *          separator;
324         int *           column;
325 {
326         int             length = strlen(string);
327
328         length += (separator ? 2 : 1);
329
330         if (((*column) + length) >= MAX_COL) {
331                 printf("\n");
332                 (*column) = 0;
333         } else if ((*column) != 0) {
334                 if (separator) {
335                         printf("%c", *separator);
336                         (*column)++;
337                 }
338                 printf(" ");
339                 (*column)++;
340         }
341
342         if ((*column) == 0) {
343                 (*column) += device_printf(dev, "%s", string);
344         } else {
345                 (*column) += printf("%s", string);
346         }
347
348         return;
349 }
350
351 static int
352 mca_print_child (device_t dev, device_t child)
353 {
354         char                            buf[MAX_COL+1];
355         struct mca_device *             m_dev = device_get_ivars(child);
356         int                             rid;
357         struct resource_list_entry *    rle;
358         char                            separator = ',';
359         int                             column = 0;
360         int                             retval = 0;
361
362         if (device_get_desc(child)) {
363                 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
364                 mca_reg_print(child, buf, NULL, &column);
365         }
366
367         rid = 0;
368         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid++))) {
369                 if (rle->count == 1) {
370                         snprintf(buf, sizeof(buf), "%s%lx",
371                                 ((rid == 1) ? "io 0x" : "0x"),
372                                 rle->start);
373                 } else {
374                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
375                                 ((rid == 1) ? "io 0x" : "0x"),
376                                 rle->start,
377                                 (rle->start + rle->count));
378                 }
379                 mca_reg_print(child, buf,
380                         ((rid == 2) ? &separator : NULL), &column);
381         }
382
383         rid = 0;
384         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid++))) {
385                 if (rle->count == 1) {
386                         snprintf(buf, sizeof(buf), "%s%lx",
387                                 ((rid == 1) ? "mem 0x" : "0x"),
388                                 rle->start);
389                 } else {
390                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
391                                 ((rid == 1) ? "mem 0x" : "0x"),
392                                 rle->start,
393                                 (rle->start + rle->count));
394                 }
395                 mca_reg_print(child, buf,
396                         ((rid == 2) ? &separator : NULL), &column);
397         }
398
399         rid = 0;
400         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid++))) {
401                 snprintf(buf, sizeof(buf), "irq %ld", rle->start);
402                 mca_reg_print(child, buf,
403                         ((rid == 1) ? &separator : NULL), &column);
404         }
405
406         rid = 0;
407         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid++))) {
408                 snprintf(buf, sizeof(buf), "drq %lx", rle->start);
409                 mca_reg_print(child, buf,
410                         ((rid == 1) ? &separator : NULL), &column);
411         }
412
413         snprintf(buf, sizeof(buf), "on %s id %04x slot %d\n",
414                 device_get_nameunit(dev),
415                 mca_get_id(child), mca_get_slot(child)+1);
416         mca_reg_print(child, buf, NULL, &column);
417
418         return (retval);
419 }
420
421 static void
422 mca_probe_nomatch (device_t dev, device_t child)
423 {
424         mca_id_t        mca_id = mca_get_id(child);
425         u_int8_t        slot = mca_get_slot(child);
426         u_int8_t        enabled = mca_get_enabled(child);
427
428         device_printf(dev, "unknown card (id 0x%04x, %s) at slot %d\n",
429                 mca_id,
430                 (enabled ? "enabled" : "disabled"),
431                 slot + 1);
432
433         return;
434 }
435
436 static int
437 mca_read_ivar (device_t dev, device_t child, int which, u_long * result)
438 {
439         struct mca_device *             m_dev = device_get_ivars(child);
440
441         switch (which) {
442                 case MCA_IVAR_SLOT:
443                         *result = m_dev->slot;
444                         break;
445                 case MCA_IVAR_ID:
446                         *result = m_dev->id;
447                         break;
448                 case MCA_IVAR_ENABLED:
449                         *result = m_dev->enabled;
450                         break;
451                 default:
452                         return (ENOENT);
453                         break;
454         }
455
456         return (0);
457 }
458
459 static int
460 mca_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
461 {
462         return (EINVAL);
463 }
464
465 static struct resource *
466 mca_alloc_resource (device_t dev, device_t child, int type, int *rid,
467                     u_long start, u_long end, u_long count, u_int flags)
468 {
469         struct mca_device *             m_dev = device_get_ivars(child);
470         struct resource_list_entry *    rle;
471         int                             isdefault;
472         int                             passthrough;
473
474         isdefault = (start == 0UL && end == ~0UL);
475         passthrough = (device_get_parent(child) != dev);
476
477         if (!passthrough && !isdefault) {
478                 rle = resource_list_find(&(m_dev->rl), type, *rid);
479                 if (!rle) {
480                         resource_list_add(&(m_dev->rl), type, *rid,
481                                           start, end, count);
482                 }
483         }
484
485         if (type == SYS_RES_IRQ) {
486                 flags |= RF_SHAREABLE;
487         }
488
489         return (resource_list_alloc(&(m_dev->rl), dev, child, type, rid,
490                                     start, end, count, flags));
491 }
492
493 static int
494 mca_release_resource (device_t dev, device_t child, int type, int rid,
495                       struct resource * r)
496 {
497         struct mca_device *             m_dev = device_get_ivars(child);
498
499         return (resource_list_release(&(m_dev->rl), dev, child, type, rid, r));
500 }
501
502 static int
503 mca_get_resource(device_t dev, device_t child, int type, int rid,
504                  u_long *startp, u_long *countp)
505 {
506         struct mca_device *             m_dev = device_get_ivars(child);
507         struct resource_list *          rl = &(m_dev->rl);
508         struct resource_list_entry *    rle;
509
510         rle = resource_list_find(rl, type, rid);
511         if (!rle)
512                 return ENOENT;
513         
514         *startp = rle->start;
515         *countp = rle->count;
516
517         return (0);
518 }
519
520 static int
521 mca_set_resource(device_t dev, device_t child, int type, int rid,
522                  u_long start, u_long count)
523 {
524         struct mca_device *             m_dev = device_get_ivars(child);
525         struct resource_list *          rl = &(m_dev->rl);
526
527         resource_list_add(rl, type, rid, start, start + count - 1, count);
528         return (0);
529 }
530
531 static void
532 mca_delete_resource(device_t dev, device_t child, int type, int rid)
533 {
534         struct mca_device *             m_dev = device_get_ivars(child);
535         struct resource_list *          rl = &(m_dev->rl);
536
537         resource_list_delete(rl, type, rid);
538 }
539
540 static struct resource_list *
541 mca_get_resource_list (device_t dev, device_t child)
542
543         struct mca_device *     m_dev = device_get_ivars(child);
544         struct resource_list *  rl = &m_dev->rl;
545
546         if (!rl)
547                 return (NULL);
548
549         return (rl);
550 }
551
552
553 static device_method_t mca_methods[] = {
554         /* Device interface */
555         DEVMETHOD(device_probe,         mca_probe),
556         DEVMETHOD(device_attach,        bus_generic_attach),
557         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
558         DEVMETHOD(device_suspend,       bus_generic_suspend),
559         DEVMETHOD(device_resume,        bus_generic_resume),
560
561         /* Bus interface */
562         DEVMETHOD(bus_print_child,      mca_print_child),
563         DEVMETHOD(bus_probe_nomatch,    mca_probe_nomatch),
564         DEVMETHOD(bus_read_ivar,        mca_read_ivar),
565         DEVMETHOD(bus_write_ivar,       mca_write_ivar),
566         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
567         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
568         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),     
569
570         DEVMETHOD(bus_get_resource_list,mca_get_resource_list),
571         DEVMETHOD(bus_alloc_resource,   mca_alloc_resource),
572         DEVMETHOD(bus_release_resource, mca_release_resource),
573         DEVMETHOD(bus_set_resource,     mca_set_resource),
574         DEVMETHOD(bus_get_resource,     mca_get_resource),
575         DEVMETHOD(bus_delete_resource,  mca_delete_resource),
576         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
577         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
578
579         { 0, 0 }
580 };
581
582 static driver_t mca_driver = {       
583         "mca",
584         mca_methods,
585         1,              /* no softc */
586 };
587
588 static devclass_t mca_devclass;
589
590 DRIVER_MODULE(mca, nexus, mca_driver, mca_devclass, 0, 0);