]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ncv/ncr53c500_pccard.c
Retire dpt(4)
[FreeBSD/FreeBSD.git] / sys / dev / ncv / ncr53c500_pccard.c
1 /*      $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $        */
2 /*      $NetBSD$        */
3
4 /*-
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * [Ported for FreeBSD]
8  *  Copyright (c) 2000
9  *      Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe.
10  *      All rights reserved.
11  * [NetBSD for NEC PC-98 series]
12  *  Copyright (c) 1995, 1996, 1997, 1998
13  *      NetBSD/pc98 porting staff. All rights reserved.
14  *  Copyright (c) 1995, 1996, 1997, 1998
15  *      Naofumi HONDA. All rights reserved.
16  * 
17  *  Redistribution and use in source and binary forms, with or without
18  *  modification, are permitted provided that the following conditions
19  *  are met:
20  *  1. Redistributions of source code must retain the above copyright
21  *     notice, this list of conditions and the following disclaimer.
22  *  2. Redistributions in binary form must reproduce the above copyright
23  *     notice, this list of conditions and the following disclaimer in the
24  *     documentation and/or other materials provided with the distribution.
25  *  3. The name of the author may not be used to endorse or promote products
26  *     derived from this software without specific prior written permission.
27  * 
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
32  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include <sys/param.h>
45 #include <sys/errno.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/module.h>
49 #include <sys/systm.h>
50
51 #include <machine/bus.h>
52 #include <machine/resource.h>
53 #include <sys/rman.h>
54 #include <compat/netbsd/dvcfg.h>
55
56 #include <sys/bus.h>
57
58 #include <dev/pccard/pccardvar.h>
59
60 #include <cam/scsi/scsi_low.h>
61
62 #include <dev/ncv/ncr53c500reg.h>
63 #include <dev/ncv/ncr53c500hw.h>
64 #include <dev/ncv/ncr53c500var.h>
65
66 #define KME_KXLC004_01 0x100
67 #define OFFSET_KME_KXLC004_01 0x10
68
69
70 #include "pccarddevs.h"
71
72 static int ncvprobe(device_t devi);
73 static int ncvattach(device_t devi);
74
75 static void     ncv_card_unload(device_t);
76
77 static const struct ncv_product {
78         struct pccard_product   prod;
79         int flags;
80 } ncv_products[] = {
81         { PCMCIA_CARD(EPSON, SC200), 0},
82         { PCMCIA_CARD(PANASONIC, KXLC002), 0xb4d00000 },
83         { PCMCIA_CARD(PANASONIC, KXLC003), 0xb4d00000 },        /* untested */
84         { PCMCIA_CARD(PANASONIC, KXLC004), 0xb4d00100 },
85         { PCMCIA_CARD(MACNICA, MPS100), 0xb6250000 },
86         { PCMCIA_CARD(MACNICA, MPS110), 0 },
87         { PCMCIA_CARD(NEC, PC9801N_J03R), 0 },
88         { PCMCIA_CARD(NEWMEDIA, BASICS_SCSI), 0 },
89         { PCMCIA_CARD(QLOGIC, PC05), 0x84d00000 },
90 #define FLAGS_REX5572 0x84d00000
91         { PCMCIA_CARD(RATOC, REX5572), FLAGS_REX5572 },
92         { PCMCIA_CARD(RATOC, REX9530), 0x84d00000 },
93         { { NULL }, 0 }
94 };
95
96 /*
97  * Additional code for FreeBSD new-bus PCCard frontend
98  */
99
100 static void
101 ncv_pccard_intr(void * arg)
102 {
103         struct ncv_softc *sc;
104
105         sc = arg;
106         SCSI_LOW_LOCK(&sc->sc_sclow);
107         ncvintr(arg);
108         SCSI_LOW_UNLOCK(&sc->sc_sclow);
109 }
110
111 static void
112 ncv_release_resource(device_t dev)
113 {
114         struct ncv_softc        *sc = device_get_softc(dev);
115
116         if (sc->ncv_intrhand) {
117                 bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand);
118         }
119
120         if (sc->port_res) {
121                 bus_release_resource(dev, SYS_RES_IOPORT,
122                                      sc->port_rid, sc->port_res);
123         }
124
125         if (sc->port_res_dmy) {
126                 bus_release_resource(dev, SYS_RES_IOPORT,
127                                      sc->port_rid_dmy, sc->port_res_dmy);
128         }
129
130         if (sc->irq_res) {
131                 bus_release_resource(dev, SYS_RES_IRQ,
132                                      sc->irq_rid, sc->irq_res);
133         }
134
135         if (sc->mem_res) {
136                 bus_release_resource(dev, SYS_RES_MEMORY,
137                                      sc->mem_rid, sc->mem_res);
138         }
139         mtx_destroy(&sc->sc_sclow.sl_lock);
140 }
141
142 static int
143 ncv_alloc_resource(device_t dev)
144 {
145         struct ncv_softc        *sc = device_get_softc(dev);
146         u_int32_t               flags = device_get_flags(dev);
147         rman_res_t              ioaddr, iosize, maddr, msize;
148         int                     error;
149         bus_addr_t              offset = 0;
150
151         if(flags & KME_KXLC004_01)
152                 offset = OFFSET_KME_KXLC004_01;
153
154         error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize);
155         if (error || (iosize < (offset + NCVIOSZ))) {
156                 return(ENOMEM);
157         }
158
159         mtx_init(&sc->sc_sclow.sl_lock, "ncv", NULL, MTX_DEF);
160         sc->port_rid = 0;
161         sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
162                                           ioaddr+offset, ioaddr+iosize-offset,
163                                           iosize-offset, RF_ACTIVE);
164         if (sc->port_res == NULL) {
165                 ncv_release_resource(dev);
166                 return(ENOMEM);
167         }
168
169         if (offset != 0) {
170                 sc->port_rid_dmy = 0;
171                 sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, 
172                                                 &sc->port_rid_dmy,
173                                                 ioaddr, ioaddr+offset, offset, 
174                                                 RF_ACTIVE);
175                 if (sc->port_res_dmy == NULL) {
176                         printf("Warning: cannot allocate IOPORT partially.\n");
177                 }
178         } else {
179                 sc->port_rid_dmy = 0;
180                 sc->port_res_dmy = NULL;
181         }
182
183         sc->irq_rid = 0;
184         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
185                                              RF_ACTIVE);
186         if (sc->irq_res == NULL) {
187                 ncv_release_resource(dev);
188                 return(ENOMEM);
189         }
190
191         error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize);
192         if (error) {
193                 return(0);      /* XXX */
194         }
195
196         /* no need to allocate memory if not configured */
197         if (maddr == 0 || msize == 0) {
198                 return(0);
199         }
200
201         sc->mem_rid = 0;
202         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
203                                              RF_ACTIVE);
204         if (sc->mem_res == NULL) {
205                 ncv_release_resource(dev);
206                 return(ENOMEM);
207         }
208
209         return(0);
210 }
211
212 static int
213 ncv_pccard_probe(device_t dev)
214 {
215         const struct ncv_product *pp;
216         const char *vendorstr;
217         const char *prodstr;
218
219         if ((pp = (const struct ncv_product *) pccard_product_lookup(dev, 
220             (const struct pccard_product *) ncv_products,
221             sizeof(ncv_products[0]), NULL)) != NULL) {
222                 if (pp->prod.pp_name != NULL)
223                         device_set_desc(dev, pp->prod.pp_name);
224                 device_set_flags(dev, pp->flags);
225                 return(0);
226         }
227         if (pccard_get_vendor_str(dev, &vendorstr))
228                 return(EIO);
229         if (pccard_get_product_str(dev, &prodstr))
230                 return(EIO);
231         if (strcmp(vendorstr, "RATOC System Inc.") == 0 &&
232                 strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) {
233                 device_set_desc(dev, "RATOC REX-5572");
234                 device_set_flags(dev, FLAGS_REX5572);
235                 return (BUS_PROBE_DEFAULT);
236         }
237         return(EIO);
238 }
239
240 static int
241 ncv_pccard_attach(device_t dev)
242 {
243         struct ncv_softc        *sc = device_get_softc(dev);
244         int                     error;
245
246         error = ncv_alloc_resource(dev);
247         if (error) {
248                 return(error);
249         }
250
251         if (ncvprobe(dev) == 0) {
252                 ncv_release_resource(dev);
253                 return(ENXIO);
254         }
255         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY |
256             INTR_MPSAFE, NULL, ncv_pccard_intr, sc, &sc->ncv_intrhand);
257         if (error) {
258                 ncv_release_resource(dev);
259                 return(error);
260         }
261
262         if (ncvattach(dev) == 0) {
263                 ncv_release_resource(dev);
264                 return(ENXIO);
265         }
266         gone_in_dev(dev, 12, "ncv(4) driver");
267
268         return(0);
269 }
270
271 static  int
272 ncv_pccard_detach(device_t dev)
273 {
274         ncv_card_unload(dev);
275         ncv_release_resource(dev);
276
277         return (0);
278 }
279
280 static device_method_t ncv_pccard_methods[] = {
281         /* Device interface */
282         DEVMETHOD(device_probe,         ncv_pccard_probe),
283         DEVMETHOD(device_attach,        ncv_pccard_attach),
284         DEVMETHOD(device_detach,        ncv_pccard_detach),
285
286         { 0, 0 }
287 };
288
289 static driver_t ncv_pccard_driver = {
290         "ncv",
291         ncv_pccard_methods,
292         sizeof(struct ncv_softc),
293 };
294
295 static devclass_t ncv_devclass;
296
297 MODULE_DEPEND(ncv, scsi_low, 1, 1, 1);
298 DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0);
299 PCCARD_PNP_INFO(ncv_products);
300
301 static void
302 ncv_card_unload(device_t devi)
303 {
304         struct ncv_softc *sc = device_get_softc(devi);
305
306         scsi_low_deactivate(&sc->sc_sclow);
307         scsi_low_detach(&sc->sc_sclow);
308 }
309
310 static int
311 ncvprobe(device_t devi)
312 {
313         int rv;
314         struct ncv_softc *sc = device_get_softc(devi);
315         u_int32_t flags = device_get_flags(devi);
316
317         rv = ncvprobesubr(sc->port_res,
318                           flags, NCV_HOSTID);
319
320         return rv;
321 }
322
323 static int
324 ncvattach(device_t devi)
325 {
326         struct ncv_softc *sc;
327         struct scsi_low_softc *slp;
328         u_int32_t flags = device_get_flags(devi);
329
330         sc = device_get_softc(devi);
331
332         slp = &sc->sc_sclow;
333         slp->sl_dev = devi;
334         slp->sl_hostid = NCV_HOSTID;
335         slp->sl_cfgflags = flags;
336
337         ncvattachsubr(sc);
338
339         return(NCVIOSZ);
340 }