Synchronize a bunch of things from FreeBSD-5 in preparation for the new
[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.4 2004/02/21 06:37:05 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) {
270                         m_dev = (struct mca_device *)malloc(sizeof(*m_dev),
271                                                             M_DEVBUF, M_NOWAIT);
272                         if (!m_dev) {
273                                 device_printf(dev, "cannot malloc mca_device");
274                                 break;
275                         }
276                 }
277                 bzero(m_dev, sizeof(*m_dev));
278
279                 /* Select adapter setup regs */
280                 outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
281
282                 /* Read the POS registers */
283                 for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
284                         m_dev->pos[reg] = inb(MCA_POS_REG(reg));
285                 }
286
287                 /* Disable adapter setup */
288                 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
289
290                 if (bootverbose) {
291                         printf("mca slot %d:", slot + 1);       
292                         for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
293                                 printf(" %02x", m_dev->pos[reg]);
294                         }
295                         printf("\n");
296                 }
297
298                 m_dev->id = (u_int16_t)m_dev->pos[MCA_POS0] |
299                             ((u_int16_t)m_dev->pos[MCA_POS1] << 8);
300
301                 if (m_dev->id == 0xffff) {
302                         continue;
303                 }
304
305                 devices_found++;
306
307                 m_dev->enabled = (m_dev->pos[MCA_POS2] & MCA_POS2_ENABLE);
308                 m_dev->slot = slot;
309
310                 resource_list_init(&(m_dev->rl));
311
312                 child = device_add_child(dev, NULL, -1);
313                 device_set_ivars(child, m_dev);
314
315                 m_dev = NULL;
316         }
317
318         if (m_dev) {
319                 free(m_dev, M_DEVBUF);
320         }
321
322         return (devices_found ? 0 : ENXIO);
323 }
324
325 static void
326 mca_reg_print (dev, string, separator, column)
327         device_t        dev;
328         char *          string;
329         char *          separator;
330         int *           column;
331 {
332         int             length = strlen(string);
333
334         length += (separator ? 2 : 1);
335
336         if (((*column) + length) >= MAX_COL) {
337                 printf("\n");
338                 (*column) = 0;
339         } else if ((*column) != 0) {
340                 if (separator) {
341                         printf("%c", *separator);
342                         (*column)++;
343                 }
344                 printf(" ");
345                 (*column)++;
346         }
347
348         if ((*column) == 0) {
349                 (*column) += device_printf(dev, "%s", string);
350         } else {
351                 (*column) += printf("%s", string);
352         }
353
354         return;
355 }
356
357 static int
358 mca_print_child (device_t dev, device_t child)
359 {
360         char                            buf[MAX_COL+1];
361         struct mca_device *             m_dev = device_get_ivars(child);
362         int                             rid;
363         struct resource_list_entry *    rle;
364         char                            separator = ',';
365         int                             column = 0;
366         int                             retval = 0;
367
368         if (device_get_desc(child)) {
369                 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
370                 mca_reg_print(child, buf, NULL, &column);
371         }
372
373         rid = 0;
374         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid++))) {
375                 if (rle->count == 1) {
376                         snprintf(buf, sizeof(buf), "%s%lx",
377                                 ((rid == 1) ? "io 0x" : "0x"),
378                                 rle->start);
379                 } else {
380                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
381                                 ((rid == 1) ? "io 0x" : "0x"),
382                                 rle->start,
383                                 (rle->start + rle->count));
384                 }
385                 mca_reg_print(child, buf,
386                         ((rid == 2) ? &separator : NULL), &column);
387         }
388
389         rid = 0;
390         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid++))) {
391                 if (rle->count == 1) {
392                         snprintf(buf, sizeof(buf), "%s%lx",
393                                 ((rid == 1) ? "mem 0x" : "0x"),
394                                 rle->start);
395                 } else {
396                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
397                                 ((rid == 1) ? "mem 0x" : "0x"),
398                                 rle->start,
399                                 (rle->start + rle->count));
400                 }
401                 mca_reg_print(child, buf,
402                         ((rid == 2) ? &separator : NULL), &column);
403         }
404
405         rid = 0;
406         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid++))) {
407                 snprintf(buf, sizeof(buf), "irq %ld", rle->start);
408                 mca_reg_print(child, buf,
409                         ((rid == 1) ? &separator : NULL), &column);
410         }
411
412         rid = 0;
413         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid++))) {
414                 snprintf(buf, sizeof(buf), "drq %lx", rle->start);
415                 mca_reg_print(child, buf,
416                         ((rid == 1) ? &separator : NULL), &column);
417         }
418
419         snprintf(buf, sizeof(buf), "on %s id %04x slot %d\n",
420                 device_get_nameunit(dev),
421                 mca_get_id(child), mca_get_slot(child)+1);
422         mca_reg_print(child, buf, NULL, &column);
423
424         return (retval);
425 }
426
427 static void
428 mca_probe_nomatch (device_t dev, device_t child)
429 {
430         mca_id_t        mca_id = mca_get_id(child);
431         u_int8_t        slot = mca_get_slot(child);
432         u_int8_t        enabled = mca_get_enabled(child);
433
434         device_printf(dev, "unknown card (id 0x%04x, %s) at slot %d\n",
435                 mca_id,
436                 (enabled ? "enabled" : "disabled"),
437                 slot + 1);
438
439         return;
440 }
441
442 static int
443 mca_read_ivar (device_t dev, device_t child, int which, u_long * result)
444 {
445         struct mca_device *             m_dev = device_get_ivars(child);
446
447         switch (which) {
448                 case MCA_IVAR_SLOT:
449                         *result = m_dev->slot;
450                         break;
451                 case MCA_IVAR_ID:
452                         *result = m_dev->id;
453                         break;
454                 case MCA_IVAR_ENABLED:
455                         *result = m_dev->enabled;
456                         break;
457                 default:
458                         return (ENOENT);
459                         break;
460         }
461
462         return (0);
463 }
464
465 static int
466 mca_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
467 {
468         return (EINVAL);
469 }
470
471 static struct resource *
472 mca_alloc_resource (device_t dev, device_t child, int type, int *rid,
473                     u_long start, u_long end, u_long count, u_int flags)
474 {
475         struct mca_device *             m_dev = device_get_ivars(child);
476         struct resource_list_entry *    rle;
477         int                             isdefault;
478         int                             passthrough;
479
480         isdefault = (start == 0UL && end == ~0UL);
481         passthrough = (device_get_parent(child) != dev);
482
483         if (!passthrough && !isdefault) {
484                 rle = resource_list_find(&(m_dev->rl), type, *rid);
485                 if (!rle) {
486                         resource_list_add(&(m_dev->rl), type, *rid,
487                                           start, end, count);
488                 }
489         }
490
491         if (type == SYS_RES_IRQ) {
492                 flags |= RF_SHAREABLE;
493         }
494
495         return (resource_list_alloc(&(m_dev->rl), dev, child, type, rid,
496                                     start, end, count, flags));
497 }
498
499 static int
500 mca_release_resource (device_t dev, device_t child, int type, int rid,
501                       struct resource * r)
502 {
503         struct mca_device *             m_dev = device_get_ivars(child);
504
505         return (resource_list_release(&(m_dev->rl), dev, child, type, rid, r));
506 }
507
508 static int
509 mca_get_resource(device_t dev, device_t child, int type, int rid,
510                  u_long *startp, u_long *countp)
511 {
512         struct mca_device *             m_dev = device_get_ivars(child);
513         struct resource_list *          rl = &(m_dev->rl);
514         struct resource_list_entry *    rle;
515
516         rle = resource_list_find(rl, type, rid);
517         if (!rle)
518                 return ENOENT;
519         
520         *startp = rle->start;
521         *countp = rle->count;
522
523         return (0);
524 }
525
526 static int
527 mca_set_resource(device_t dev, device_t child, int type, int rid,
528                  u_long start, u_long count)
529 {
530         struct mca_device *             m_dev = device_get_ivars(child);
531         struct resource_list *          rl = &(m_dev->rl);
532
533         resource_list_add(rl, type, rid, start, start + count - 1, count);
534         return (0);
535 }
536
537 static void
538 mca_delete_resource(device_t dev, device_t child, int type, int rid)
539 {
540         struct mca_device *             m_dev = device_get_ivars(child);
541         struct resource_list *          rl = &(m_dev->rl);
542
543         resource_list_delete(rl, type, rid);
544 }
545
546 static struct resource_list *
547 mca_get_resource_list (device_t dev, device_t child)
548
549         struct mca_device *     m_dev = device_get_ivars(child);
550         struct resource_list *  rl = &m_dev->rl;
551
552         if (!rl)
553                 return (NULL);
554
555         return (rl);
556 }
557
558
559 static device_method_t mca_methods[] = {
560         /* Device interface */
561         DEVMETHOD(device_probe,         mca_probe),
562         DEVMETHOD(device_attach,        bus_generic_attach),
563         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
564         DEVMETHOD(device_suspend,       bus_generic_suspend),
565         DEVMETHOD(device_resume,        bus_generic_resume),
566
567         /* Bus interface */
568         DEVMETHOD(bus_print_child,      mca_print_child),
569         DEVMETHOD(bus_probe_nomatch,    mca_probe_nomatch),
570         DEVMETHOD(bus_read_ivar,        mca_read_ivar),
571         DEVMETHOD(bus_write_ivar,       mca_write_ivar),
572         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
573         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
574         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),     
575
576         DEVMETHOD(bus_get_resource_list,mca_get_resource_list),
577         DEVMETHOD(bus_alloc_resource,   mca_alloc_resource),
578         DEVMETHOD(bus_release_resource, mca_release_resource),
579         DEVMETHOD(bus_set_resource,     mca_set_resource),
580         DEVMETHOD(bus_get_resource,     mca_get_resource),
581         DEVMETHOD(bus_delete_resource,  mca_delete_resource),
582         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
583         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
584
585         { 0, 0 }
586 };
587
588 static driver_t mca_driver = {       
589         "mca",
590         mca_methods,
591         1,              /* no softc */
592 };
593
594 static devclass_t mca_devclass;
595
596 DRIVER_MODULE(mca, nexus, mca_driver, mca_devclass, 0, 0);