Initial import from FreeBSD RELENG_4:
[games.git] / sys / bus / isa / i386 / isa.c
1 /*-
2  * Copyright (c) 1998 Doug Rabson
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/i386/isa/isa.c,v 1.132.2.5 2002/03/03 05:42:50 nyan Exp $
27  */
28
29 /*
30  * Modifications for Intel architecture by Garrett A. Wollman.
31  * Copyright 1998 Massachusetts Institute of Technology
32  *
33  * Permission to use, copy, modify, and distribute this software and
34  * its documentation for any purpose and without fee is hereby
35  * granted, provided that both the above copyright notice and this
36  * permission notice appear in all copies, that both the above
37  * copyright notice and this permission notice appear in all
38  * supporting documentation, and that the name of M.I.T. not be used
39  * in advertising or publicity pertaining to distribution of the
40  * software without specific, written prior permission.  M.I.T. makes
41  * no representations about the suitability of this software for any
42  * purpose.  It is provided "as is" without express or implied
43  * warranty.
44  * 
45  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
46  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
47  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
48  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
49  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
55  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  */
58
59 #include <sys/param.h>
60 #include <sys/bus.h>
61 #include <sys/malloc.h>
62 #include <machine/bus.h>
63 #include <sys/rman.h>
64
65 #include <machine/resource.h>
66
67 #include <isa/isavar.h>
68 #include <isa/isa_common.h>
69
70 void
71 isa_init(void)
72 {
73     isa_wrap_old_drivers();
74 }
75
76 /*
77  * This implementation simply passes the request up to the parent
78  * bus, which in our case is the special i386 nexus, substituting any
79  * configured values if the caller defaulted.  We can get away with
80  * this because there is no special mapping for ISA resources on an Intel
81  * platform.  When porting this code to another architecture, it may be
82  * necessary to interpose a mapping layer here.
83  */
84 struct resource *
85 isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
86                    u_long start, u_long end, u_long count, u_int flags)
87 {
88         /*
89          * Consider adding a resource definition. We allow rid 0-1 for
90          * irq and drq, 0-3 for memory and 0-7 for ports which is
91          * sufficient for isapnp.
92          */
93         int passthrough = (device_get_parent(child) != bus);
94         int isdefault = (start == 0UL && end == ~0UL);
95         struct isa_device* idev = DEVTOISA(child);
96         struct resource_list *rl = &idev->id_resources;
97         struct resource_list_entry *rle;
98         
99         if (!passthrough && !isdefault) {
100                 rle = resource_list_find(rl, type, *rid);
101                 if (!rle) {
102                         if (*rid < 0)
103                                 return 0;
104                         switch (type) {
105                         case SYS_RES_IRQ:
106                                 if (*rid >= ISA_NIRQ)
107                                         return 0;
108                                 break;
109                         case SYS_RES_DRQ:
110                                 if (*rid >= ISA_NDRQ)
111                                         return 0;
112                                 break;
113                         case SYS_RES_MEMORY:
114                                 if (*rid >= ISA_NMEM)
115                                         return 0;
116                                 break;
117                         case SYS_RES_IOPORT:
118                                 if (*rid >= ISA_NPORT)
119                                         return 0;
120                                 break;
121                         default:
122                                 return 0;
123                         }
124                         resource_list_add(rl, type, *rid, start, end, count);
125                 }
126         }
127
128         return resource_list_alloc(rl, bus, child, type, rid,
129                                    start, end, count, flags);
130 }
131
132 #ifdef PC98
133 /*
134  * Indirection support.  The type of bus_space_handle_t is
135  * defined in sys/i386/include/bus_pc98.h.
136  */
137 struct resource *
138 isa_alloc_resourcev(device_t child, int type, int *rid,
139                     bus_addr_t *res, bus_size_t count, u_int flags)
140 {
141         struct isa_device* idev = DEVTOISA(child);
142         struct resource_list *rl = &idev->id_resources;
143
144         device_t        bus = device_get_parent(child);
145         bus_addr_t      start;
146         struct resource *re;
147         struct resource **bsre;
148         int             i, j, k, linear_cnt, ressz, bsrid;
149
150         start = bus_get_resource_start(child, type, *rid);
151
152         linear_cnt = count;
153         ressz = 1;
154         for (i = 1; i < count; ++i) {
155                 if (res[i] != res[i - 1] + 1) {
156                         if (i < linear_cnt)
157                                 linear_cnt = i;
158                         ++ressz;
159                 }
160         }
161
162         re = isa_alloc_resource(bus, child, type, rid,
163                                 start + res[0], start + res[linear_cnt - 1],
164                                 linear_cnt, flags);
165         if (re == NULL)
166                 return NULL;
167
168         bsre = malloc(sizeof (struct resource *) * ressz, M_DEVBUF, M_NOWAIT);
169         if (bsre == NULL) {
170                 resource_list_release(rl, bus, child, type, *rid, re);
171                 return NULL;
172         }
173         bsre[0] = re;
174
175         for (i = linear_cnt, k = 1; i < count; i = j, k++) {
176                 for (j = i + 1; j < count; j++) {
177                         if (res[j] != res[j - 1] + 1)
178                                 break;
179                 }
180                 bsrid = *rid + k;
181                 bsre[k] = isa_alloc_resource(bus, child, type, &bsrid,
182                         start + res[i], start + res[j - 1], j - i, flags);
183                 if (bsre[k] == NULL) {
184                         for (k--; k >= 0; k--)
185                                 resource_list_release(rl, bus, child, type,
186                                                       *rid + k, bsre[k]);
187                         free(bsre, M_DEVBUF);
188                         return NULL;
189                 }
190         }
191
192         re->r_bushandle->bsh_res = bsre;
193         re->r_bushandle->bsh_ressz = ressz;
194
195         return re;
196 }
197
198 int
199 isa_load_resourcev(struct resource *re, bus_addr_t *res, bus_size_t count)
200 {
201         bus_addr_t      start;
202         int             i;
203
204         if (count > re->r_bushandle->bsh_maxiatsz) {
205                 printf("isa_load_resourcev: map size too large\n");
206                 return EINVAL;
207         }
208
209         start = rman_get_start(re);
210         for (i = 0; i < re->r_bushandle->bsh_maxiatsz; i++) {
211                 if (i < count)
212                         re->r_bushandle->bsh_iat[i] = start + res[i];
213                 else
214                         re->r_bushandle->bsh_iat[i] = start;
215         }
216
217         re->r_bushandle->bsh_iatsz = count;
218         re->r_bushandle->bsh_bam = re->r_bustag->bs_ra; /* relocate access */
219
220         return 0;
221 }
222 #endif  /* PC98 */
223
224 int
225 isa_release_resource(device_t bus, device_t child, int type, int rid,
226                      struct resource *r)
227 {
228         struct isa_device* idev = DEVTOISA(child);
229         struct resource_list *rl = &idev->id_resources;
230 #ifdef PC98
231         /*
232          * Indirection support.  The type of bus_space_handle_t is
233          * defined in sys/i386/include/bus_pc98.h.
234          */
235         int     i;
236
237         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
238                 for (i = 1; i < r->r_bushandle->bsh_ressz; i++)
239                         resource_list_release(rl, bus, child, type, rid + i,
240                                               r->r_bushandle->bsh_res[i]);
241                 if (r->r_bushandle->bsh_res != NULL)
242                         free(r->r_bushandle->bsh_res, M_DEVBUF);
243         }
244 #endif
245         return resource_list_release(rl, bus, child, type, rid, r);
246 }
247
248 /*
249  * We can't use the bus_generic_* versions of these methods because those
250  * methods always pass the bus param as the requesting device, and we need
251  * to pass the child (the i386 nexus knows about this and is prepared to
252  * deal).
253  */
254 int
255 isa_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
256                void (*ihand)(void *), void *arg, void **cookiep)
257 {
258         return (BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
259                                ihand, arg, cookiep));
260 }
261
262 int
263 isa_teardown_intr(device_t bus, device_t child, struct resource *r,
264                   void *cookie)
265 {
266         return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, cookie));
267 }