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