]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/ncv/ncr53c500_pccard.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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/systm.h>
47
48 #include <machine/bus.h>
49 #include <machine/resource.h>
50 #include <sys/rman.h>
51 #include <compat/netbsd/dvcfg.h>
52
53 #include <sys/device_port.h>
54
55 #include <dev/pccard/pccardvar.h>
56
57 #include <cam/scsi/scsi_low.h>
58 #include <cam/scsi/scsi_low_pisa.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(DEVPORT_PDEVICE devi);
71 static int ncvattach(DEVPORT_PDEVICE devi);
72
73 static void     ncv_card_unload(DEVPORT_PDEVICE);
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         ncvintr(arg);
102 }
103
104 static void
105 ncv_release_resource(DEVPORT_PDEVICE dev)
106 {
107         struct ncv_softc        *sc = device_get_softc(dev);
108
109         if (sc->ncv_intrhand) {
110                 bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand);
111         }
112
113         if (sc->port_res) {
114                 bus_release_resource(dev, SYS_RES_IOPORT,
115                                      sc->port_rid, sc->port_res);
116         }
117
118         if (sc->port_res_dmy) {
119                 bus_release_resource(dev, SYS_RES_IOPORT,
120                                      sc->port_rid_dmy, sc->port_res_dmy);
121         }
122
123         if (sc->irq_res) {
124                 bus_release_resource(dev, SYS_RES_IRQ,
125                                      sc->irq_rid, sc->irq_res);
126         }
127
128         if (sc->mem_res) {
129                 bus_release_resource(dev, SYS_RES_MEMORY,
130                                      sc->mem_rid, sc->mem_res);
131         }
132 }
133
134 static int
135 ncv_alloc_resource(DEVPORT_PDEVICE dev)
136 {
137         struct ncv_softc        *sc = device_get_softc(dev);
138         u_int32_t               flags = DEVPORT_PDEVFLAGS(dev);
139         u_long                  ioaddr, iosize, maddr, msize;
140         int                     error;
141         bus_addr_t              offset = 0;
142
143         if(flags & KME_KXLC004_01)
144                 offset = OFFSET_KME_KXLC004_01;
145
146         error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize);
147         if (error || (iosize < (offset + NCVIOSZ))) {
148                 return(ENOMEM);
149         }
150
151         sc->port_rid = 0;
152         sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
153                                           ioaddr+offset, ioaddr+iosize-offset,
154                                           iosize-offset, RF_ACTIVE);
155         if (sc->port_res == NULL) {
156                 ncv_release_resource(dev);
157                 return(ENOMEM);
158         }
159
160         if (offset != 0) {
161                 sc->port_rid_dmy = 0;
162                 sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, 
163                                                 &sc->port_rid_dmy,
164                                                 ioaddr, ioaddr+offset, offset, 
165                                                 RF_ACTIVE);
166                 if (sc->port_res_dmy == NULL) {
167                         printf("Warning: cannot allocate IOPORT partially.\n");
168                 }
169         } else {
170                 sc->port_rid_dmy = 0;
171                 sc->port_res_dmy = NULL;
172         }
173
174         sc->irq_rid = 0;
175         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
176                                              RF_ACTIVE);
177         if (sc->irq_res == NULL) {
178                 ncv_release_resource(dev);
179                 return(ENOMEM);
180         }
181
182         error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize);
183         if (error) {
184                 return(0);      /* XXX */
185         }
186
187         /* no need to allocate memory if not configured */
188         if (maddr == 0 || msize == 0) {
189                 return(0);
190         }
191
192         sc->mem_rid = 0;
193         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
194                                              RF_ACTIVE);
195         if (sc->mem_res == NULL) {
196                 ncv_release_resource(dev);
197                 return(ENOMEM);
198         }
199
200         return(0);
201 }
202
203 static int
204 ncv_pccard_probe(device_t dev)
205 {
206         const struct ncv_product *pp;
207         const char *vendorstr;
208         const char *prodstr;
209
210         if ((pp = (const struct ncv_product *) pccard_product_lookup(dev, 
211             (const struct pccard_product *) ncv_products,
212             sizeof(ncv_products[0]), NULL)) != NULL) {
213                 if (pp->prod.pp_name != NULL)
214                         device_set_desc(dev, pp->prod.pp_name);
215                 device_set_flags(dev, pp->flags);
216                 return(0);
217         }
218         if (pccard_get_vendor_str(dev, &vendorstr))
219                 return(EIO);
220         if (pccard_get_product_str(dev, &prodstr))
221                 return(EIO);
222         if (strcmp(vendorstr, "RATOC System Inc.") == 0 &&
223                 strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) {
224                 device_set_desc(dev, "RATOC REX-5572");
225                 device_set_flags(dev, FLAGS_REX5572);
226                 return (0);
227         }
228         return(EIO);
229 }
230
231 static int
232 ncv_pccard_attach(device_t dev)
233 {
234         struct ncv_softc        *sc = device_get_softc(dev);
235         int                     error;
236
237         bzero(sc, sizeof(struct ncv_softc));
238
239         error = ncv_alloc_resource(dev);
240         if (error) {
241                 return(error);
242         }
243
244         if (ncvprobe(dev) == 0) {
245                 ncv_release_resource(dev);
246                 return(ENXIO);
247         }
248         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY,
249                                NULL, ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand);
250         if (error) {
251                 ncv_release_resource(dev);
252                 return(error);
253         }
254
255         if (ncvattach(dev) == 0) {
256                 ncv_release_resource(dev);
257                 return(ENXIO);
258         }
259
260         return(0);
261 }
262
263 static  int
264 ncv_pccard_detach(device_t dev)
265 {
266         ncv_card_unload(dev);
267         ncv_release_resource(dev);
268
269         return (0);
270 }
271
272 static device_method_t ncv_pccard_methods[] = {
273         /* Device interface */
274         DEVMETHOD(device_probe,         ncv_pccard_probe),
275         DEVMETHOD(device_attach,        ncv_pccard_attach),
276         DEVMETHOD(device_detach,        ncv_pccard_detach),
277
278         { 0, 0 }
279 };
280
281 static driver_t ncv_pccard_driver = {
282         "ncv",
283         ncv_pccard_methods,
284         sizeof(struct ncv_softc),
285 };
286
287 static devclass_t ncv_devclass;
288
289 MODULE_DEPEND(ncv, scsi_low, 1, 1, 1);
290 DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0);
291
292 static void
293 ncv_card_unload(DEVPORT_PDEVICE devi)
294 {
295         struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
296         intrmask_t s;
297
298         s = splcam();
299         scsi_low_deactivate((struct scsi_low_softc *)sc);
300         scsi_low_dettach(&sc->sc_sclow);
301         splx(s);
302 }
303
304 static int
305 ncvprobe(DEVPORT_PDEVICE devi)
306 {
307         int rv;
308         struct ncv_softc *sc = device_get_softc(devi);
309         u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
310
311         rv = ncvprobesubr(rman_get_bustag(sc->port_res),
312                           rman_get_bushandle(sc->port_res),
313                           flags, NCV_HOSTID);
314
315         return rv;
316 }
317
318 static int
319 ncvattach(DEVPORT_PDEVICE devi)
320 {
321         struct ncv_softc *sc;
322         struct scsi_low_softc *slp;
323         u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
324         intrmask_t s;
325         char dvname[16]; /* SCSI_LOW_DVNAME_LEN */
326
327         strcpy(dvname, "ncv");
328
329         sc = DEVPORT_PDEVALLOC_SOFTC(devi);
330         if (sc == NULL) {
331                 return(0);
332         }
333
334         slp = &sc->sc_sclow;
335         slp->sl_dev = devi;
336         sc->sc_iot = rman_get_bustag(sc->port_res);
337         sc->sc_ioh = rman_get_bushandle(sc->port_res);
338
339         slp->sl_hostid = NCV_HOSTID;
340         slp->sl_cfgflags = flags;
341
342         s = splcam();
343         ncvattachsubr(sc);
344         splx(s);
345
346         return(NCVIOSZ);
347 }