]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mca/mca_bus.c
This commit was generated by cvs2svn to compensate for changes in r51885,
[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 mca_device {
59         mca_id_t        id;
60         u_int8_t        slot;
61         u_int8_t        enabled;
62         u_int8_t        pos[8];         /* Programable Option Select Regs. */
63
64         struct resource_list rl;        /* Resources */
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         struct mca_device *     m_dev = NULL;
249         int                     devices_found = 0;
250         u_int8_t                slot;
251         u_int8_t                reg;
252
253         device_set_desc(dev, "MCA bus");
254
255         /* Disable adapter setup */
256         outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
257         /* Disable motherboard setup */
258         outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
259
260         if (bootverbose) {
261                 printf("POS REG     00 01 02 03 04 05 06 07\n");
262                 printf("-----------------------------------\n");
263         }
264
265         for (slot = 0; slot < MCA_MAX_SLOTS; slot++) {
266
267                 if (!m_dev) {
268                         m_dev = (struct mca_device *)malloc(sizeof(*m_dev),
269                                                             M_DEVBUF, M_NOWAIT);
270                         if (!m_dev) {
271                                 device_printf(dev, "cannot malloc mca_device");
272                                 break;
273                         }
274                 }
275                 bzero(m_dev, sizeof(*m_dev));
276
277                 /* Select adapter setup regs */
278                 outb(MCA_ADAP_SETUP_REG, ((slot & 0x0f) | MCA_ADAP_SET));
279
280                 /* Read the POS registers */
281                 for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
282                         m_dev->pos[reg] = inb(MCA_POS_REG(reg));
283                 }
284
285                 /* Disable adapter setup */
286                 outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
287
288                 if (bootverbose) {
289                         printf("mca slot %d:", slot + 1);       
290                         for (reg = MCA_POS0; reg <= MCA_POS7; reg++) {
291                                 printf(" %02x", m_dev->pos[reg]);
292                         }
293                         printf("\n");
294                 }
295
296                 m_dev->id = (u_int16_t)m_dev->pos[MCA_POS0] |
297                             ((u_int16_t)m_dev->pos[MCA_POS1] << 8);
298
299                 if (m_dev->id == 0xffff) {
300                         continue;
301                 }
302
303                 devices_found++;
304
305                 m_dev->enabled = (m_dev->pos[MCA_POS2] & MCA_POS2_ENABLE);
306                 m_dev->slot = slot;
307
308                 resource_list_init(&(m_dev->rl));
309
310                 device_add_child(dev, NULL, -1, m_dev);
311
312                 m_dev = NULL;
313         }
314
315         if (m_dev) {
316                 free(m_dev, M_DEVBUF);
317         }
318
319         return (devices_found ? 0 : ENXIO);
320 }
321
322 static void
323 mca_reg_print (dev, string, separator, column)
324         device_t        dev;
325         char *          string;
326         char *          separator;
327         int *           column;
328 {
329         int             length = strlen(string);
330
331         length += (separator ? 2 : 1);
332
333         if (((*column) + length) >= MAX_COL) {
334                 printf("\n");
335                 (*column) = 0;
336         } else if ((*column) != 0) {
337                 if (separator) {
338                         printf("%c", *separator);
339                         (*column)++;
340                 }
341                 printf(" ");
342                 (*column)++;
343         }
344
345         if ((*column) == 0) {
346                 (*column) += device_printf(dev, "%s", string);
347         } else {
348                 (*column) += printf("%s", string);
349         }
350
351         return;
352 }
353
354 static int
355 mca_print_child (device_t dev, device_t child)
356 {
357         char                            buf[MAX_COL+1];
358         struct mca_device *             m_dev = device_get_ivars(child);
359         int                             rid;
360         struct resource_list_entry *    rle;
361         char                            separator = ',';
362         int                             column = 0;
363         int                             retval = 0;
364
365         if (device_get_desc(child)) {
366                 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
367                 mca_reg_print(child, buf, NULL, &column);
368         }
369
370         rid = 0;
371         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid++))) {
372                 if (rle->count == 1) {
373                         snprintf(buf, sizeof(buf), "%s%lx",
374                                 ((rid == 1) ? "io 0x" : "0x"),
375                                 rle->start);
376                 } else {
377                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
378                                 ((rid == 1) ? "io 0x" : "0x"),
379                                 rle->start,
380                                 (rle->start + rle->count));
381                 }
382                 mca_reg_print(child, buf,
383                         ((rid == 2) ? &separator : NULL), &column);
384         }
385
386         rid = 0;
387         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid++))) {
388                 if (rle->count == 1) {
389                         snprintf(buf, sizeof(buf), "%s%lx",
390                                 ((rid == 1) ? "mem 0x" : "0x"),
391                                 rle->start);
392                 } else {
393                         snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
394                                 ((rid == 1) ? "mem 0x" : "0x"),
395                                 rle->start,
396                                 (rle->start + rle->count));
397                 }
398                 mca_reg_print(child, buf,
399                         ((rid == 2) ? &separator : NULL), &column);
400         }
401
402         rid = 0;
403         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid++))) {
404                 snprintf(buf, sizeof(buf), "irq %ld", rle->start);
405                 mca_reg_print(child, buf,
406                         ((rid == 1) ? &separator : NULL), &column);
407         }
408
409         rid = 0;
410         while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid++))) {
411                 snprintf(buf, sizeof(buf), "drq %lx", rle->start);
412                 mca_reg_print(child, buf,
413                         ((rid == 1) ? &separator : NULL), &column);
414         }
415
416         snprintf(buf, sizeof(buf), "on %s id %04x slot %d\n",
417                 device_get_nameunit(dev),
418                 mca_get_id(child), mca_get_slot(child)+1);
419         mca_reg_print(child, buf, NULL, &column);
420
421         return (retval);
422 }
423
424 static void
425 mca_probe_nomatch (device_t dev, device_t child)
426 {
427         mca_id_t        mca_id = mca_get_id(child);
428         u_int8_t        slot = mca_get_slot(child);
429         u_int8_t        enabled = mca_get_enabled(child);
430
431         device_printf(dev, "unknown card (id 0x%04x, %s) at slot %d\n",
432                 mca_id,
433                 (enabled ? "enabled" : "disabled"),
434                 slot + 1);
435
436         return;
437 }
438
439 static int
440 mca_read_ivar (device_t dev, device_t child, int which, u_long * result)
441 {
442         struct mca_device *             m_dev = device_get_ivars(child);
443         struct resource_list_entry *    rle;
444
445         switch (which) {
446                 case MCA_IVAR_SLOT:
447                         *result = m_dev->slot;
448                         break;
449                 case MCA_IVAR_ID:
450                         *result = m_dev->id;
451                         break;
452                 case MCA_IVAR_ENABLED:
453                         *result = m_dev->enabled;
454                         break;
455                 default:
456                         return (ENOENT);
457                         break;
458         }
459
460         return (0);
461 }
462
463 static int
464 mca_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
465 {
466         return (EINVAL);
467 }
468
469 static struct resource *
470 mca_alloc_resource (device_t dev, device_t child, int type, int *rid,
471                     u_long start, u_long end, u_long count, u_int flags)
472 {
473         struct mca_device *             m_dev = device_get_ivars(child);
474         struct resource_list_entry *    rle;
475         int                             isdefault;
476         int                             passthrough;
477
478         isdefault = (start == 0UL && end == ~0UL);
479         passthrough = (device_get_parent(child) != dev);
480
481         if (!passthrough && !isdefault) {
482                 rle = resource_list_find(&(m_dev->rl), type, *rid);
483                 if (!rle) {
484                         resource_list_add(&(m_dev->rl), type, *rid,
485                                           start, end, count);
486                 }
487         }
488
489         return (resource_list_alloc(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         return (resource_list_release(dev, child, type, rid, r));
498 }
499
500 static device_method_t mca_methods[] = {
501         /* Device interface */
502         DEVMETHOD(device_probe,         mca_probe),
503         DEVMETHOD(device_attach,        bus_generic_attach),
504         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
505         DEVMETHOD(device_suspend,       bus_generic_suspend),
506         DEVMETHOD(device_resume,        bus_generic_resume),
507
508         /* Bus interface */
509         DEVMETHOD(bus_print_child,      mca_print_child),
510         DEVMETHOD(bus_probe_nomatch,    mca_probe_nomatch),
511         DEVMETHOD(bus_read_ivar,        mca_read_ivar),
512         DEVMETHOD(bus_write_ivar,       mca_write_ivar),
513         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
514         DEVMETHOD(bus_alloc_resource,   mca_alloc_resource),
515         DEVMETHOD(bus_release_resource, mca_release_resource),
516         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
517         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
518         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
519         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),     
520
521         { 0, 0 }
522 };
523
524 static driver_t mca_driver = {       
525         "mca",
526         mca_methods,
527         1,              /* no softc */
528 };
529
530 static devclass_t mca_devclass;
531
532 DRIVER_MODULE(mca, nexus, mca_driver, mca_devclass, 0, 0);